文章目录
步骤
1.自定义注解 @CheckLogin
package com.itmuch.usercenter.auth;
/**
* 校验登录的注解
* @author mikasa
*/
public @interface CheckLogin {
}
2.对要拦截的方法加上@CheckLogin注解
@GetMapping("/{id}")
@CheckLogin
public User findById(@PathVariable Integer id) {
log.info("我被请求了...");
return this.userService.findById(id);
}
3.定义切面拦截校验
/**
* 登录拦截切面
* @author mikasa
*/
@Aspect
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AuthAspect {
/**
* 校验token的工具类
*/
private final JwtOperator jwtOperator;
@Around("@annotation(com.itmuch.usercenter.auth.CheckLogin)")
public Object checkLogin(ProceedingJoinPoint point) throws Throwable {
checkToken();
return point.proceed();
}
private void checkToken() {
try {
// 1. 从header里面获取token
HttpServletRequest request = getHttpServletRequest();
String token = request.getHeader("X-Token");
// 2. 校验token是否合法&是否过期;如果不合法或已过期直接抛异常;如果合法放行
Boolean isValid = jwtOperator.validateToken(token);
if (!isValid) {
throw new SecurityException("Token不合法!");
}
// 3. 如果校验成功,那么就将用户的信息设置到request的attribute里面
Claims claims = jwtOperator.getClaimsFromToken(token);
request.setAttribute("id", claims.get("id"));
request.setAttribute("wxNickname", claims.get("wxNickname"));
request.setAttribute("role", claims.get("role"));
} catch (Throwable throwable) {
throw new SecurityException("Token不合法");
}
}
/**
* RequestContextHolder静态方法获取RequestAttributes
* @return HttpServletRequest
*/
private HttpServletRequest getHttpServletRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
return attributes.getRequest();
}
4.失败返回异常提示处理
package com.itmuch.usercenter.auth;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author mikasa
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionErrorHandler {
@ExceptionHandler(SecurityException.class)
public ResponseEntity<ErrorBody> error(SecurityException e) {
log.warn("发生SecurityException异常", e);
return new ResponseEntity<>(
ErrorBody.builder()
.body(e.getMessage())
.status(HttpStatus.UNAUTHORIZED.value())
.build(),
HttpStatus.UNAUTHORIZED
);
}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class ErrorBody {
private String body;
private int status;
}
知识点
@annotation
概念:是一个AspectJ切点函数,它可以用于匹配带有指定注解的方法
用法:@annotation(自定义注解的全限定名/xxx.class)
@Around("@annotation(com.mikasa.usercenter.auth.CheckLogin/CheckLogin.class)")
public Object checkLogin(ProceedingJoinPoint joinPoint) throws Throwable {
// ...
}
回忆切点表达式:
execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])
// controler包下的所有以Controller结尾的类的任意方法
@Around("execution(* com.mikasa.usercenter.controller.*Controller.*(..))
RequestContextHolder:
概念:是一个Spring框架提供的工具类,它可以用于获取当前请求的上下文信息。
API: 静态方法getRequestAttributes(),它可以用于获取当前请求的ServletRequestAttributes对象。
ServletRequestAttributes: 包含了当前请求的所有信息,例如请求头、请求参数、请求体等
private HttpServletRequest getHttpServletRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
return attributes.getRequest();
}
@RestControllerAdvice
概念:Spring框架中的一个注解,用于定义一个全局的异常处理器。当Web服务中发生异常时,@RestControllerAdvice注解的类可以处理异常并返回HTTP响应。
使用:使用@RestControllerAdvice注解的类可以包含多个方法,每个方法都可以处理不同的异常类型。这些方法应该使用**@ExceptionHandler**注解来声明处理的异常类型。
意义:在处理异常时,@RestControllerAdvice类可以返回自定义的HTTP响应或其他类型的响应体,例如JSON或XML。这使得开发人员可以在发生异常时向客户端提供更有意义的响应,而不仅仅是简单的错误消息。