超强的SpringBoot接口自定义访问权限验证方案一

109 阅读1分钟

1. 项目环境

后端:SpringBoot
前端:Vue2
框架:若依管理系统

2. 需求

接口对外开放,需要验证访问者身份。
因为若依系统中已经整合了JWT,所以咱们也是用JWT生成token用于身份验证。所有接口使用AOP拦截校验,

3. 生成Token

配置文件,user为访问用户标识,这里写死,也可以做成配置项。

token:
  key: 1234567891234567833456
  user: 测试用户

public class GenJwtUtil {

    /**
     * 生成JWT
     */
    public static String createJWT(String id, String subject, String key) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder().setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                .signWith(SignatureAlgorithm.HS256, key);
        return builder.compact();
    }

    /**
     * 解析JWT
     */
    public static Claims parseJWT(String jwtStr, String key) {
        return Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwtStr)
                .getBody();
    }

}

使用createJWT第一个参数固定写死。

@Value("${token.key}")
private String key;
@Value("${token.user}")
    
String token = AppJwtUtil.createJWT("999", user, key);

4. 接口使用

@TestAuthentication
@GetMapping("/test")
public AjaxResult test() {
    return AjaxResult.success()
}

5. 注解定义

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAuthentication {
}

6. 切面

@Slf4j
@Aspect
@Component
public class TestAuthenticationAspect {

    @Value("${token.key}")
    private String key;
    @Value("${token.user}")


    @Around("execution(* com..controller..*.*(..)) " +
            "&& @annotation(com.test.common.annotation.TestAuthentication) " +
            "&& (@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.GetMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.PostMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.PutMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.PatchMapping))"
    )
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
            String token = request.getHeader("TOKEN");
            if (StringUtils.isBlank(token)) {
                throw new GlobalException("无权限访问");
            }

            try {
                Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
                String subject = claims.getSubject();
                if (StringUtils.isBlank(subject) || !StringUtils.equals(subject, user)) {
                    throw new GlobalException("无权限访问");
                }
            } catch (Exception e) {
                throw new GlobalException("解析token失败");
            }
            return pjp.proceed();
        } catch (Throwable e) {
            throw e;
        }
    }
}

至此结束,整个验权流程比较简单,有很大的改进空间,如果项目要求没有那么严格可以使用本方案,也可以在该方案上进行改进,比如生成token时用户数据改为从数据库查询、设置token过期时间等等。