五分钟入门入门JWT

本文详细介绍了JWT在无状态认证中的应用,对比传统session,如何通过JSON Web Tokens实现用户身份验证,降低服务器资源消耗并提升扩展性。使用Spring Boot示例展示JWT的生成、验证和信息获取过程。
摘要由CSDN通过智能技术生成

JWT入门级教程

传统的session实现方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jLdeujuh-1629359081114)(C:\Users\村长\AppData\Roaming\Typora\typora-user-images\image-20210817144124462.png)]

1.随着平台用户增多,存储在服务器上面的session的越多,会占用服务器资源,用户量大,会导致频繁出发GC(可以设置过期时间)
2.限制了扩展性,session是保存在服务器上面的,那对于分布式服务,就意味着他只能从这台机器中获取。(当然你可以用redis存储session,但是会导致服务器开销,用token的话 可以完美解决这个问题)
3.session是基于cookie来确定用户的身份的,但cookie容易被截取,跨站请求的伪造攻击(攻击者盗用了你的身份,以你的名义发送恶意请求。)

session实现原理

用户进行登录请求,服务端会返回一个jessionID给客户端,客户端保存这个jesseionID,然后下次请求的时候,把这个jessionID放在请求头中,服务端就会进行验证,就知道这个人是谁。

token的认证机制

用户请求登录的时候,他会生成一个token,然后返回给客户端,客户端将这个token存储在浏览器中,然后下次访问的时候,在头部加入这个token就行了,服务端不需要存储任何东西,你只要把token传递过来了,后端就会进行解密,分析,不会占用服务器资源。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-luZEUlqu-1629359039090)(C:\Users\村长\AppData\Roaming\Typora\typora-user-images\image-20210817150038662.png)]

JWT构成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zuJJe1MK-1629359039093)(C:\Users\村长\AppData\Roaming\Typora\typora-user-images\image-20210817151004682.png)]

head

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PWGGBec5-1629359039094)(C:\Users\村长\AppData\Roaming\Typora\typora-user-images\image-20210817151030393.png)]

playload

就是负载 用来存放用户一些不敏感信息 例如用户id 用户名在这里插入图片描述
你也可以在负荷添加一些其他的信息
在这里插入图片描述

signature

在这里插入图片描述

JWT实战

pom.xml

		<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.7.0</version>
        </dependency>
        

完整案例

package com.cz.testmail.security;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.*;
import com.cz.testmail.Vo.User;
import org.springframework.stereotype.Component;
import java.util.Date;


@Component
public class TokenUtils {
    // 1:定义加密的盐信息 enc
    private static final String KEY = "nHnds.sg47hskgpl";
    // 2:发行者
    private static final String ISSUSER = "cz";
    // 3:定义token的过期时间                       秒     分    小时  天   月
    public static final Long TOKEN_EXPIRE_TIME = 1000 * 60 * 60 * 24 * 30L;
    //加密
    private static Algorithm algorithm = Algorithm.HMAC256(KEY);
    
   /*   1 :header --确定算法和类型
       2 :payload --确定要加密的数据
      3 :sign --把header和payload + 盐 进行同一组合生成一个token
     有状态:服务端来维护你的数据信息,消耗的服务器资源
     无状态:服务段不维护你数据信息,不会消耗服务器资源*/
    public static String getToken(User user) {
        // token签发的时间
        Date now = new Date();
        // 1: 开始创建和生成token token1 == token2
        String token = JWT.create()
                .withIssuer(ISSUSER) // 签发者
                .withIssuedAt(now)// token签发的时间
                .withExpiresAt(new Date(now.getTime() + TOKEN_EXPIRE_TIME)) // 设定jwt的服务器过期时间
                .withClaim("username", user.getUserName())
                .withClaim("userid", user.getUserId())
                .sign(algorithm);
        System.out.println(user.getUserId());
        return token;
    }

    /**
     * 验证token
     *
     * @param token
     * @param username
     * @return
     */
    public static JSONObject verify(String token, String username) {
        JSONObject jsonObject=new JSONObject();
        try {
            // 1: 定义算法
            Algorithm algorithm = Algorithm.HMAC256(KEY);
            // 2: 进行校验  你这里就是根据用户名来效验  它这里会自动进行反解密   把token的东西
            // 反解密出来  跟username进行一个比较   这里定义的username需要跟你上面携带的claim一直
            JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer(ISSUSER)
                    .withClaim("username", username).build();
            jwtVerifier.verify(token);// 如果校验成功,不做任何动作 ,如果校验失败就抛出异常
            jsonObject.put("code",200);
            return   jsonObject;
        } catch (Exception ex) {
            System.out.println(ex);
            System.out.println("抛异常");
            jsonObject.put("code",500);
            return  jsonObject;
        }
    }
    //  直接根据token进行效验 不判断用户是谁
    public static JSONObject verifyToken(String token){
        JSONObject jsonObject1=new JSONObject();
        try {
            // 1: 定义算法
            Algorithm algorithm = Algorithm.HMAC256(KEY);
            JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer(ISSUSER).build();
            jwtVerifier.verify(token);// 如果校验成功,不做任何动作 ,如果校验失败就抛出异常
            jsonObject1.put("code",200);
            return   jsonObject1;
        } catch (Exception ex) {
            System.out.println(ex);
            System.out.println("抛异常");
            jsonObject1.put("code",500);
            return  jsonObject1;
        }
    }
    /**
     **   获取token中的用户信息
     *@Author  cz
     *@Date 2021/8/19 14:27
     *@Param
     */
    public static String getUserInfoToken(String token){

        JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer(ISSUSER).build();
        DecodedJWT verify = jwtVerifier.verify(token);// 如果校验成功,不做任何动作 ,如果校验失败就抛出异常
        Claim claim1 = verify.getClaim("userid");
        System.out.println(claim1.asInt());

        Claim claim = verify.getClaim("username");
        System.out.println(claim.asString()+"username");

        return  "根据你自己需求返回";

    }

    public static void main(String[] args) {
        User user = new User();
        user.setUserName("test");
        user.setUserId(1);
        String token = getToken(user);
        System.out.println(TokenUtils.verifyToken(token));
        System.out.println("=========");

       System.out.println(getUserInfoToken(token));
    }
}

拦截器

前端将token放入header中,拦截器进行解析,正确即往下执行。

 @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (request.getRequestURI().contains("login"))  {
            return true;
        }
        System.out.println("开始拦截");
        //拿到请求链接中包含的数据
        String  userName= getParam(request,"userName");
        //拿到请求头中的token
        String token = getParam(request,"Authorization");
        //会检验token是否过期
        TokenUtils.verify(token,userName);
        System.out.println("用户验证成功");
        return true;
    }
    public static String getParam(HttpServletRequest request, String filedName) {
        //1 :在参数里面区获取对应filedName的值
        String param = request.getParameter(filedName);
        // 2:如果不存在
        if (StringUtils.isEmpty(param)) {
            // 3: 就请求头区获取对应filedName的值
            param = request.getHeader(filedName);
        }
        return param;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值