JWT令牌检验用户是否登录

文章目录

JWT检验用户是否登录

由于session存储在服务器内存中,集群和分布式的存在使session无法在不同机器中共同使用,因此session中不适合存用户个人信息

JWT介绍

JWT官网
JWT (JSON WEB TOKEN)是一种以令牌传输的信息传递方式,类似于一张医院就诊卡,包含了用户的全部信息.

JWT由三部分组成:

  1. Header (头部),声明了使用的算法

  2. Payload (载荷),传输的数据内容

  3. Signature (签名),让服务器校验这个令牌是没有被别人修改的,不被伪造的(签名部分是和前两部分结合放伪的 )

JWT 将头部和载荷部分进行Base64Url编码 (编码解码都是公开的,这里面的数据是不保密的),拼接字符串,然后将前两部分和服务器独有的秘钥 加进算法 中生成签名 ,这三部分通过编码以字符串token的形式,在客户端暂存.

A + B = C

一旦A(数据)被改变,B永远在服务器当中不可改变,那么C就不同,就能知道A是被篡改过的,不是自身服务器生成的.

当然,JWT本身是解决集群和分布式的问题.用户数据信息本身就不在JWT中被加密保护,对用户信息保密需要采用其他的安全手段

JWT使用

1. 引入依赖

xml 复制代码
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId> <!-- 或 jjwt-gson -->
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

2. 生成token

生成token之前,先配置 一下秘钥

  • 秘钥Key由一串字符串封装而成 ,这个字符串有长度的要求以确保不被破解,我们更推荐直接让系统生成符合对应算法的字符串
  • SecretKey继承了Key这个父类,Key是非对称加密,SercretKey是对称加密,方便解密拿到数据内容.
  • secretKey本质是字符串,可以互相转变,为了以后能够用这个secretKey解密拿数据,我们把它的字符串存下来,这个字符串就作为每一次生成和解密的秘钥;
java 复制代码
	//private static final String str1 = "sjdad789fdsdja9s8djsf90a";//自己写一个字符串
    //private static final SecretKey key1 = Keys.hmacShaKeyFor(Decoders.BASE64.decode(str1));//通过这个字符串构建key
    
    //更推荐使用系统帮我们生成SecretKey,一次使用,终身受益
    SecretKey secretKey1 = Keys.secretKeyFor(SignatureAlgorithm.HS256);//参数指定加密算法
    //将这个秘钥转换回字符串,建议打印出这个字符串保存为常量
    String keyString = Encoders.BASE64.encode(secretKey1.getEncoded());
    private static final SecretKey secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(keyString));//通过这个字符串构建key
    
    

另外

  • token可以配置签发时间和过期时间;
  • 传入的数据Claims继承Map<String,Object>
    public interface Claims extends Map<String, Object>, Identifiable {-----}
java 复制代码
private static final long JWT_EXPIRATION = 60*60*1000;//配置过期的时长
public static String genJwtToken(Map<String, Object> claim){
        Date now = new Date();
        String token = Jwts.builder()//得到一个构造器
                .claims(claim) //需要传入一个map数据
                .issuedAt(now) // 当前签发时间
                .expiration(new Date(now.getTime() + JWT_EXPIRATION)) // 过期时间
                .signWith(secretKey1) // 使用密钥签名
                .compact();//将上面的配置结合
        return token;
    }

3. 通过token拿取数据

java 复制代码
public static Claims parseToken(String token){
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .verifyWith(sercretkey) // 使用同一密钥验签
                    .build()  //通过秘钥生成解析器
                    .parseSignedClaims(token) // 验签并解析
                    .getPayload(); //拿到token第二部分里的数据
        }catch (Exception e){
            log.error("解析token失败, token:{}", token);
            return null;
        }
        return claims;
    }

4. 登录之后发放token

java 复制代码
public Result login(String userName, String password){
		//-------------
		//在一系列的登录校验之后成功登录,发放token
        Map<String,Object> userInfoMap = new HashMap<>();
        //token里可以放一些用户的基本信息,比如id和用户名,不建议放敏感信息
        userInfoMap.put("id",userInfo.getId());
        userInfoMap.put("userName",userInfo.getUserName());
        String token= JwtUtils.genJwtToken(userInfoMap);
        return Result.success(token);
 }

将token发给前端,前端将token保存到cookie上,后续每一次请求都发送token.

5. 配置拦截器拦截前逻辑

java 复制代码
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //处理拦截之前的逻辑
        //如果客户端是将token放在请求头中的
        String token = request.getHeader("user_token_header");//这个字符串是前端设置的主键,内容是token
        log.info("正在验证token,token->{}", token);
        if(JwtUtils.parseToken(token) == null){
            log.info("token无效,请重新登录");
            response.setStatus(401);//未授权
            return false;
        }
        return true;
    }
}

6.添加拦截器到spring

java 复制代码
@Configuration //注入拦截器到spring容器
public class LoginConfig implements WebMvcConfigurer {
    @Autowired
    LoginInterceptor loginInterceptor;

    private List<String> list = Arrays.asList(
            "/user/login",
            "/user/register",
            "/**/*.html",
            "/css/**",
            "/js/**",
            "/pic/**",
            "/blog-editormd/**",
            "/favicon.ico"
    );

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加拦截器
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**") //拦截所有请求
                .excludePathPatterns(list); //传入一个list统计需要排除的接口
    }
}
相关推荐
一氧化二氢.h1 小时前
【简单理解】数组、数组列表、集合
java
哆啦A梦15881 小时前
11,Springboot3+vue3个人中心,修改密码
java·前端·javascript·数据库·vue3
小则又沐风a1 小时前
C++模板进阶
java·服务器·前端·c++
段ヤシ.1 小时前
回顾Java知识点,面试题汇总Day3(持续更新)
java·开发语言·windows
庞轩px1 小时前
第三篇:SpringMVC——一个HTTP请求在Spring中经历了什么?
网络协议·spring·http·springmvc·handlermapping·前端控制器
woai33642 小时前
项目-轻客管家1-环境准备
java
xqqxqxxq9 小时前
Java AI智能P图工具技术笔记
java·人工智能·笔记
谷雨不太卷9 小时前
进程的状态码
java·前端·算法
顾温9 小时前
default——C#/C++
java·c++·c#