基于 AOP 和 JWT 实现的 Token 身份认证组件

2 篇文章 0 订阅

基于 AOP 和 JWT 实现的 Token 身份认证组件

原理

基于 AOP 面向切面编程,在执行前后插入身份认证的逻辑。

原理细节:

  • 登录过程:这个过程比较简单,将用户 id、用户名、过期时间等属性结合 jwt 工具生成 token,并将用户的信息存入到缓存中,以供后期使用。

  • 验证过程:前端通过 Header 头信息的 Authorization 属性得到 Token,先进行 token 验证,再结合缓存验证,验证成功的话,将用户 id 和用户名等信息存入 ThreadLocal 中,这样在执行切面逻辑的时候。就可以从 ThreadLocal 中获取数据了,如UserManager.getUserId();执行完成后需要清除 ThreadLocal 中的数据;代码如下

class ValidateLoginAspect {

  @Around("pointCutMethod()")
  public Object preHandle(ProceedingJoinPoint pjp) {
    // ......
    UserContextHolder.getInstance().setContext(userMap);
    final Object proceed;
    try {
      proceed = pjp.proceed();
    } finally {
      UserContextHolder.getInstance().clear();
    }
    return proceed;
  }
}
  • 认证接口的范围:给 BaseTokenController这个基类添加 @ValidateLogin
    可以实现一个效果,只要自己的 Controller 继承了BaseTokenController,那么就不用再声明@ValidateLogin注解,自定义Controller中的 mapping 都需要身份认证。
    (PS:这样就免去了繁琐配置:如在拦截器中通过通配符的方式配置哪些接口需要拦截,哪些接口需要放行)

服务端使用方式

添加依赖


<dependency>
    <groupId>com.lyloou</groupId>
    <artifactId>component-security-loginvalidator-starter</artifactId>
    <version>${lyloou.component.version}</version>
</dependency>
  1. 继承BaseTokenController类。 因为这个类被@ValidateLogin标记,所以其下的所有子类都需要身份认证(具体实现细节,查看ValidateLoginAspect)。

@RestController
public class UserController extends BaseTokenController {

    // 从父类继承了ValidateLogin,需要身份验证
    @GetMapping("/ping")
    public String ping() {
        final Integer userId = currentUserId();
        System.out.println(userId);
        return "pong";
    }

}
  1. 如果继承了 BaseTokenController 类,又希望其中的某个方法不要被拦截,可以在方法上标记 @IgnoreValidateLogin

@RestController
public class UserController extends BaseTokenController {

    @Autowired
    TokenService tokenService;

    // 手动忽略身份验证
    @IgnoreValidateLogin
    @GetMapping("/login")
    public String login(String userId, String username) {

        Map<String, String> map = new HashMap<>();
        map.put("userId", userId);
        map.put("userName", username);
        map.put("userAvatar", "http://cdn.lyloou.com/a.jpg");

        final String token = tokenService.createToken(userId, username, JSONUtil.toJsonStr(map));
        return token;
    }
}
  1. 如果没有继承 BaseTokenController,又希望在其中某个方法中做身份认证,获取用户 id,可以在方法上标记@ValidateLogin

@RestController
public class UserController {


    // 手动添加身份验证
    @ValidateLogin
    @GetMapping("userinfo")
    public Map<String, String> userInfo() {
        Map<String, String> map = new HashMap<>();
        map.put(UserManager.X_USER_ID, UserManager.getUserId() + "");
        map.put(UserManager.X_USER_IP, UserManager.getUserIP());
        map.put(UserManager.X_USER_NAME, UserManager.getUserName());
        map.put(UserManager.X_USER_INFO, UserManager.getUserInfo());
        return map;
    }
}

使用自定义的缓存

默认使用了内存缓存ConcurrentHashMap(单机版本的)

也可以自定义缓存

/**
 * @author lilou
 * @since 2021/7/14
 */
@Service
public class RedisCodeCache implements DataCache {

    @Autowired
    private RedisService redisService;
    @Autowired
    private TokenProperties tokenProperties

    @Override
    public void set(String key, String value) {
        set(key, value, tokenProperties.getExpireSecond());
    }

    @Override
    public void set(String key, String value, long timeout) {
        redisService.set(key, value, (int) timeout);
    }

    @Override
    public String get(String key) {
        return redisService.get(key);
    }

    @Override
    public void remove(String key) {
        redisService.del(key);
    }

    @Override
    public boolean containsKey(String key) {
        return redisService.exists(key);
    }
}

客户端使用

在 Header 中配置身份认证 Token 的信息:
如:Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Mjg4MzQ3MjQsImV4cCI6MTYyOTQzOTUyNCwieC11c2VyLW5hbWUiOiJhYmNkZSIsIngtdXNlci1pZCI6IjEifQ.x0nIhSUPfxC5FlnzJ-MmJvLnJv7w5ZvFzGlNphdSByE

测试

登录接口:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PwizcGCB-1628841233198)(https://raw.githubusercontent.com/lyloou/img/develop/img/20210813155146.png)]

获取用户信息接口:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-azfG97qN-1628841233199)(https://raw.githubusercontent.com/lyloou/img/develop/img/20210813155327.png)]

源码实现

component/component-security-loginvalidator-starter at master · lyloou/component

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值