Springboot结合Jwt做前端Token的验证
说明
我们在写项目的时候,前端的API接口会在请求头携带Token,而我们后端会从请求头中获取到Token的值,然后从Token中获取用户编号,过期时间等信息,去验证这个Token是否合法,是否过期。然后给前端响应数据库中的数据。这个时候如果每个请求都去做校验,那么代码量会非常大,所以我们在Springboot中可以用Spring的AOP思路来实现,
思路
每次前端在访问服务器的API接口的时候。我们就用AOP的思想做一个切点,就是在访问API前,我们从请求头中获取Token信息,然后做验证,如果验证成功,我就去做查询数据库信息,做响应处理。否则不做处理。直接404.
这个时候我们就需要用到注解了:
代码
import java.lang.annotation.*;
/**
* 前端Token校验的注解
* @author RossZhang
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthorizedAnnotation {
String value() default "";
}
注解写好了。接下来就是AOP切点和切面的实现了
import com.blj.lesson.aop.annotation.AuthorizedAnnotation;
import com.blj.lesson.constants.Constant;
import com.blj.lesson.exception.BusinessException;
import com.blj.lesson.exception.code.BaseResponseCode;
import com.blj.lesson.utils.JwtTokenUtil;
import com.blj.lesson.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
/**
* @description: 验证Tokend的AOP
* @author: zjf
* @create: 2020-09-25 13:34
**/
@Aspect
@Order
@Component
@Slf4j
public class VerifyTokenAspect {
/**
* 请求切点方法(已提供@RequestMapping,@GetMapping,@PostMapping注解,需要其它请增加)
* 此处的切点是注解的方式
* 只要出现 @LogAnnotation注解都会进入
*/
@Pointcut(" @annotation(org.springframework.web.bind.annotation.RequestMapping) || " +
" @annotation(org.springframework.web.bind.annotation.GetMapping) || " +
" @annotation(org.springframework.web.bind.annotation.PostMapping)")
//还可以写成下面这个样子,
//@Pointcut("@annotation(com.blj.lesson.aop.annotation.AuthorizedAnnotation )")
void requestMapping() {
}
/**
* 范围切点方法
*/
@Pointcut("execution(* com.blj.lesson.web.controller.*Controller.*(..))")
public void methodPointCut() {
}
/**
* 某个方法执行前进行请求合法性认证 注入Authorized注解 (先)
*/
@Before("requestMapping() && methodPointCut() && @annotation(authorized)")
void doBefore(JoinPoint joinPoint, AuthorizedAnnotation authorized) throws Exception{
Class type = joinPoint.getSignature().getDeclaringType();
Annotation[] annotations = type.getAnnotationsByType(AuthorizedAnnotation.class);
if (annotations != null && annotations.length > 0){
log.info("进入AOP方法认证...");
authLogic(joinPoint);
}
}
/**
* 认证逻辑
* @param joinPoint
* @throws Exception
*/
private void authLogic(JoinPoint joinPoint) throws Exception {
log.info("认证开始...");
String classType = joinPoint.getTarget().getClass().getName();
Class<?> clazz = Class.forName(classType);
String clazzName = clazz.getName();
String methodName = joinPoint.getSignature().getName();
log.info("ClassName: "+clazzName);
log.info("MethodName:"+methodName);
//获取当前http请求
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//从请求头中获取authorization
String token = request.getHeader("authorization");
/**
* 校验令牌
*/
if(!JwtUtil.validateToken(token)){
log.error("前端Token被篡改");
throw new BusinessException(BaseResponseCode.FRONT_TOKEN_HAS_EXPIRED);
}
if (JwtUtil.isTokenExpired(token)){
log.error("前端Token已经过期");
throw new BusinessException(BaseResponseCode.FRONT_TOKEN_HAS_EXPIRED);
}
log.info("前端Token校验通过");
}
}
最后我们在给前端的Controller控制器的方法或者类上直接使用该注解。接可以了
@RestController
@Api(tags = "组织模块-用户管理")
@RequestMapping("/sys")
@AuthorizedAnnotation
public class UserController {
@PostMapping("/users")
@ApiOperation(value = "分页获取用户列表接口")
@AuthorizedAnnotation
public DataResult<PageVO<SysUser>> pageInfo(@RequestBody UserPageReqVO vo){
DataResult<PageVO<SysUser>> result=DataResult.success();
result.setData(userService.pageInfo(vo));
return result;
}
}
备注:
AOP,还可以做日志的保存功能。还有好多。我都不知道,望大神能为吾解惑。感激之情,溢于言表。
做日志保存的话。代码和Token验证差不多。只需要修改上面代码中authLogic方法中的功能即可。