SpringBoot登录认证实现

JWT

主要作用:

防止在未登录的情况下,可以访问到其他资源

实现思路:

代码实现:

引入jwt坐标

在存放工具类的utils包下,创建一个JwtUtil类

public class JwtUtil {

    private static final String KEY = "itheima";
	
	//接收业务数据,生成token并返回
    public static String genToken(Map<String, Object> claims) {
        return JWT.create()
                .withClaim("claims", claims)//可以用来存储用户名和用户id,存储什么可由自己决定
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))//登录令牌的有效时间设置,以毫秒为单位
                .sign(Algorithm.HMAC256(KEY));//密钥
    }

	//接收token,验证token,并返回业务数据
    public static Map<String, Object> parseToken(String token) {
        return JWT.require(Algorithm.HMAC256(KEY))
                .build()
                .verify(token)
                .getClaim("claims")
                .asMap();
    }

}

 具体实现:

与redis一起使用

 

redis

主要作用:

解决修改密码后旧令牌不会失效的问题

主要实现思路:

登录成功后,给浏览器响应令牌的同时,把该令牌存储到redis中(结合JWT)

            //登录成功
            //获取令牌token
            Map<String,Object> claims = new HashMap<>();
            claims.put("id",loginUser.getId());
            claims.put("username",loginUser.getUsername());
            String token = JwtUtil.genToken(claims);
            //把token存储到redis中
            ValueOperations<String,String> operations = stringRedisTemplate.opsForValue();
            operations.set(token,token,1, TimeUnit.HOURS);//名字,内容,后两个参数是用来设置token在redis的存放时间
            return Result.success(token);

LoginInterceptor拦截器中,需要验证浏览器携带的令牌,并同时需要获取到redis中存储的与之相同的令牌

在Interceptor包下,创建一个拦截器类为LoginInterceptor(ps:token会存放在请求头中,Authorization中)

@Component
public class LoginInterceptor implements HandlerInterceptor {
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        String token = request.getHeader("Authorization");
        //验证token
        try {
            //从redis中获取相同的token
            ValueOperations<String,String> operations = stringRedisTemplate.opsForValue();
            String redisToken = operations.get(token);//通过名字在redis中获取token
            if(redisToken==null){
                //Token已经失效了
                throw new Exception();
            }
            Map<String,Object> claims = JwtUtil.parseToken(token);
            //将业务数据存到ThreadLocal中
            ThreadLocalUtil.set(claims);
            return true;
        } catch (Exception e) {
            //http的响应状态码为401
            response.setStatus(401);
            //不放行
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清空ThreadLocalUtillocal中的数据
        ThreadLocalUtil.remove();
    }
}

同时创建一个config包,里面创建一个名为WebConfig的类,设置不拦截登录和注册页面

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        //登录接口和注册接口不拦截
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
    }
}

 

 当用户修改密码成功后,删除redis中存储的旧令牌

//3.删除redis中对应的token
         ValueOperations<String,String> operations= stringRedisTemplate.opsForValue();
         operations.getOperations().delete(token);

Thread Local

主要作用:

Thread Local 提供线程局部变量,用来存取数据: set()/get(),在拦截器登录完成之后,就利用工具类的set方法,将token中的claim数据存放进去,方便每次的使用,但用完记得调用remove方法释放。

实现思路:

代码实现:

在存放工具类的utils包下,创建一个Thread Local类

@Component
public class LoginInterceptor implements HandlerInterceptor {
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        String token = request.getHeader("Authorization");
        //验证token
        try {
            //从redis中获取相同的token
            ValueOperations<String,String> operations = stringRedisTemplate.opsForValue();
            String redisToken = operations.get(token);//通过名字在redis中获取token
            if(redisToken==null){
                //Token已经失效了
                throw new Exception();
            }
            Map<String,Object> claims = JwtUtil.parseToken(token);
            //将业务数据存到ThreadLocal中
            ThreadLocalUtil.set(claims);
            return true;
        } catch (Exception e) {
            //http的响应状态码为401
            response.setStatus(401);
            //不放行
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清空ThreadLocalUtillocal中的数据
        ThreadLocalUtil.remove();
    }
}

总结:

引入jwt坐标

创建jwt工具类

写登录成功后的代码,给浏览器响应令牌的同时,把该令牌存储到redis中

创建拦截器,在拦截器中,获取到redis中存储的与之相同的令牌,将业务数据claim存放到Thread Local中(创建Thread Local工具类),同时配置拦截器不拦截登录和注册页面

当用户修改密码成功后,删除redis中存储的旧令牌

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值