实现授权功能
- 现在我们已经完成了用户身份凭证的校验以及登录的状态保持,并且我们也知道了如何获取当前登录用户(从Session中获取)的信息,接下来,用户访问系统需要经过授权,即需要完成如下功能:
- 匿名用户(未登录用户)访问拦截:禁止匿名用户访问某些资源。
- 登录用户访问拦截:根据用户的权限决定是否能访问某些资源。
- (1)增加权限数据
- 为了实现这样的功能,我们需要在UserDto里增加权限属性,用于表示该登录用户所拥有的权限,同时修改UserDto的构造方法。
/**
* 用户身份信息
*/
@Data
@AllArgsConstructor
public class UserDto {
public static final String SESSION_USER_KEY = "_user";
private String id;
private String username;
private String password;
private String fullname;
private String mobile;
/**
* 用户权限
*/
private Set<String> authorities;
}
- 并在AuthenticationServletImpl中为模拟用户初始化权限,其中张三给了p1权限,李四给了p2权限。
/**
* 用户信息
*/
private Map<String,UserDto> userDtoMap=new HashMap<>();
{
Set<String> authorities1=new HashSet<>();
authorities1.add("p1");//这个p1我们认为让它和/r/r1对应
Set<String> authorities2=new HashSet<>();
authorities2.add("p2");//这个p1我们认为让它和/r/r2对应
userDtoMap.put("zs",new UserDto("1010","zs","123","张三","1224443",authorities1));
userDtoMap.put("ls",new UserDto("1011","ls","123","李四","1224443",authorities2));
}
- (2)添加测试资源
- 我们想实现针对不同用户能访问不同的资源,前提是得有多个资源,因此在LoginController中增加测试资源2。
@RequestMapping(value = "/r/r2", produces = "text/plain;charset=utf-8")
public String r2(HttpSession session) {
String fullname = null;
Object object = session.getAttribute(UserDto.SESSION_USER_KEY);
if (object == null) {
fullname = "匿名";
} else {
UserDto userDto = (UserDto) object;
fullname = userDto.getFullname();
}
return fullname + "访问资源r2";
}
- (实现授权拦截器)
- 在interceptor包下定义SimpleAuthenticationInterceptor拦截器,实现授权拦截:
- 1.校验用户是否登录
- 2.校验用户是否拥有操作权限
@Component
public class SimpleAuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//在这个方法中校验用户请求得url是否在用户得权限范围内
//取出用户得身份信息
Object object = request.getSession().getAttribute(UserDto.SESSION_USER_KEY);
if (object==null){
//没有认证,提示登录
writeContent(response,"请登录");
}
UserDto userDto= (UserDto) object;
//请求的url
String requestURI = request.getRequestURI();
if (userDto.getAuthorities().contains("p1")&&requestURI.contains("r/r1")){
return true;
}
if (userDto.getAuthorities().contains("p2")&&requestURI.contains("r/r2")){
return true;
}
writeContent(response,"没有权限,拒绝访问");
return false;
}
/**
* 响应信息给客户端
* @param response
* @param msg
*/
private void writeContent(HttpServletResponse response, String msg) throws IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(msg);
writer.close();
response.resetBuffer();
}
}
- 在WebConfig中配置拦截器,匹配/r/**的资源为受保护的系统资源,访问资源的请求进入SimpleAuthenticationInterceptor拦截器。
@Autowired
SimpleAuthenticationInterceptor simpleAuthenticationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(simpleAuthenticationInterceptor);
}