使用拦截器实现用户登录权限的统一校验
1、Spring AOP用户统一登录验证的问题
原生Spring AOP实现统一拦截的难点:
1、定义拦截的规则(表达式)难;
2、在切面类中拿到HttpSession难
解决方法:使用Spring拦截器
2、Spring拦截器
2.1、实现一个普通拦截器
a.实现HandlerInterceptor接口
b.重写preHandle(执行具体方法之前的预处理)方法
public class LoginInterceptor implements HandlerInterceptor {
/*
此方法返回一个boolean,如果为true,表示验证成功,可以继续执行后续流程
如果为false,表示验证失败,不能继续执行后续流程
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//用户登录业务判断
HttpSession session= request.getSession(false);
if (session!=null && session.getAttribute("userinfo")!=null){
//用户登录
return true;
}
//返回登录页面
response.sendRedirect("/login.html");
return false;
}
}
2.2、将拦截器添加到配置文件中,并且设置拦截的规则
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") //拦截所有请求
.excludePathPatterns("/user/login") //排除的url地址
.excludePathPatterns("/user/reg");
.excludePathPatterns("/**/*.html");
}
}
@RestController
@RequestMapping("/user")
public class UserController {
// @GetMapping
// public String getMethod(){
// return "执行 GET 请求方式";
// }
//
// @PostMapping
// public String postMethod(){
// return "执行 POST 请求方式";
// }
@RequestMapping("/getuser")
public String getUser(){
System.out.println("执行了get User");
return "get user";
}
@RequestMapping("/login")
public String login(){
System.out.println("执行了login");
return "login";
}
@RequestMapping("/reg")
public String reg(){
System.out.println("执行了reg");
return "reg";
}
}
3、拦截器实现原理
4、给当前项目配置统一的前缀
4.1、在系统的配置文件中设置
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/baekhyun",c->true);
}
4.2、在application.properies配置
server.servlet.context-path=/baekhyun
统一异常的返回
-
创建一个类,并在类上标识@ControllerAdvice
@ControllerAdvice
public class MyExHandler {
}
2.添加方法来订阅异常
@ExceptionHandler(NullPointerException.class)
public HashMap<String,Object> nullException(NullPointerException e){
HashMap<String,Object> result=new HashMap<>();
result.put("code","-1");
result.put("msg","空指针异常:"+e.getMessage()); //错误码的描述信息
result.put("data",null);
return result;
}
@ExceptionHandler(Exception.class)
public HashMap<String,Object> exception(Exception e){
HashMap<String,Object> result=new HashMap<>();
result.put("code","-1");
result.put("msg","异常:"+e.getMessage()); //错误码的描述信息
result.put("data",null);
return result;
}
统一数据格式的返回
-
创建一个类,并添加@ControllerAdvice
@ControllerAdvice
public class ResponseAdvice {
}
2.实现ResponseAdvicce接口,并重写supports和beforeBodyWrite(统一对象在此方法实现)
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Autowired
private ObjectMapper objectMapper;
/*
此方法返回true则执行beforeBodyWrite方法
反之不执行
*/
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
HashMap<String,Object> result=new HashMap<>();
result.put("code",200);
result.put("msg","");
result.put("data",body);
if (body instanceof String){
//需要特殊处理,String在转换时会报错
try {
return objectMapper.writeValueAsString(result);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return result;
}
}