JAVA使用JWT生成token

定义

JWT(JSON Web Token)简而言之,JWT是一个加密的字符串,JWT传输的信息经过了数字签名,因此传输的信息可以被验证和信任。一般被用来在身份提供者和服务提供者间传递被认证用户的身份信息,以便于从资源服务器获取资源,也可以增加一些额外的业务逻辑所需的声明信息。

验证流程

使用基于Token的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:

  1. 客户端使用用户名和密码请求登录
  2. 服务端收到请求,去验证用户名和密码
  3. 验证成功后,服务端会签发一个Token,再把这个Token发送给客户端
  4. 客户端收到Token以后可以把它存储起来,比如放到Cookie里或者Local Storage里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据

组成部分

JWT 标准的 Token 由三个部分组成:header.payload.signature:

header(头部)
payload(数据)
signature(签名)

Header

头部数据,里面包含了使用的算法。

声明类型,这里是jwt
声明加密的算法 通常直接使用 HS256

{
  "alg": "HS256",
  "typ": "JWT"
}

在base64url编码之后变成

eyJhbGciOiJIUzI1NiJ9

playload

载荷是存放有效信息的地方。
iss: Issuer,发行者
sub: Subject,主题
aud: Audience,观众
exp: Expiration time 过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

可以自定义字段, 一个是 id ,还有一个是 admin 。

{
 "iss": "ninghao.net",
 "exp": "1438955445",
 "id": "aaa",
 "admin": true
}

使用 base64url 编码以后就变成了这个样子:

eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ

signature

一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)

secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密。

const encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); 
// 这里的 HMACSHA256() 就是我们在第一部分定义的加密算法。
HS256(encodedString, 'secret');

处理完像这样

SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

最后这个在服务端生成并且要发送给客户端的 Token

eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

客户端收到这个 Token 以后把它存储下来,下回向服务端发送请求的时候就带着这个 Token。服务端收到这个 Token ,然后进行验证,通过以后就会返回给客户端想要的资源。

代码如下

相关依赖

	<dependency>
		<groupId>com.auth0</groupId>
		<artifactId>java-jwt</artifactId>
		<version>3.4.0</version>
	</dependency>
token生成和验证
public class TokenUtil {
    /**
     * token过期时间
     */
    private static final long EXPIRE_TIME = 30 * 60 * 1000;
    /**
     * token秘钥
     */
    private static final String SECRET = "demo_secret";


    /**
     * 生成签名,30分钟过期
     * @param username 用户名
     * @param loginTime 登录时间
     * @return 生成的token
     */
    public static String sign(String username, String loginTime) {
        try {
            // 设置过期时间
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("Type", "Jwt");
            header.put("alg", "HS256");
            // 返回token字符串
            return JWT.create()
                    .withHeader(header)
                    .withClaim("loginName", username)
                    .withClaim("loginTime", loginTime)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 检验token是否正确
     * @param token 需要校验的token
     * @return 校验是否成功
     */
    public static boolean verify(String token){
        try {
            //设置签名的加密算法:HMAC256
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e){
            return false;
        }
    }
}
登录
/**
     * 登录
     * @param loginVo 登录类
     * @return 返回类
     */
    @Override
    public R login(LoginVo loginVo) {
        User user = new User();
        user.setUserName(loginVo.getUserName());
        user.setPassword(loginVo.getPassword());
        List<User> users = userService.queryByUser(user);
        if(users.isEmpty()){
            return R.fail();
        }else{
            if(loginVo.getUserName() != null && loginVo.getLoginTime() != null) {
                String token = TokenUtil.sign(loginVo.getUserName(), loginVo.getLoginTime());
                loginVo.setToken(token);
                //断言token不为空,并以用户名作为key,存入redis(看需求是否要放到redis)
                assert token != null;
                redisTemplate.opsForValue().set(loginVo.getUserName(),token);
                return R.ok(loginVo);
            }else{
                return R.fail();
            }
        }
    }
添加拦截器类
@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }

        response.setCharacterEncoding("utf-8");
        // header里面的字段名取决于前端放置的字段名
        String token = request.getHeader("Authorization");
        if (token != null) {
            boolean result = TokenUtil.verify(token);
            if (result) {
                System.out.println("通过拦截器");
                return true;
            }
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            JSONObject json = new JSONObject();
            json.put("success", "false");
            json.put("msg", "认证失败,未通过拦截器");
            json.put("code", "500");
            response.getWriter().append(json.toJSONString());
            System.out.println("认证失败,未通过拦截器");
        } catch (Exception e) {
            e.printStackTrace();
            response.sendError(500);
            return false;
        }
        return false;

    }
}
添加配置拦截器的类

@Component
public class IntercepterConfig implements WebMvcConfigurer {

    private TokenInterceptor tokenInterceptor;

    //构造方法
    public IntercepterConfig(TokenInterceptor tokenInterceptor){
        this.tokenInterceptor = tokenInterceptor;
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        List<String> excludePath = new ArrayList<>();
        //登录
        excludePath.add("/login/acount");
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(excludePath);
        //除了登陆接口其他所有接口都需要token验证
        WebMvcConfigurer.super.addInterceptors(registry);

    }

}

参考博客:

https://www.cnblogs.com/yuanchangliang/p/16373162.html

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java中,可以使用com.auth0库来实现JWT生成和验证。首先,你需要在你的项目中添加该库的依赖: ```xml <!--JWT--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency> ``` 接下来,你可以使用以下代码创建一个JWTtoken: ```java String token = JWTUtils.createToken(1L); ``` 请注意,在上面的例子中,我将token的过期时间设置为10秒。 接下来,如果你想验证token并获取其中的信息,你可以使用以下代码: ```java try { Map<String, Claim> stringClaimMap = JWTUtils.verifyToken(token); Long id = stringClaimMap.get("id").asLong(); System.err.println("用户id是:" + id); } catch (Exception e) { e.printStackTrace(); } ``` 上面的代码会尝试验证token,并从中获取id这个字段的值。如果token已经过期,会抛出TokenExpiredException异常。 为了处理token过期的情况,你可以使用以下代码: ```java try { // 上面的token被我设置成了10秒过期 Thread.sleep(11000L); JWTUtils.verifyToken(token); // 这里定向捕获登录过期异常 } catch (TokenExpiredException e) { // 写过期逻辑 System.err.println("登录过期"); } catch (Exception e) { e.printStackTrace(); } ``` 上面的代码会捕获TokenExpiredException异常,你可以在此处编写处理过期逻辑。 最后,你可以使用以下代码来验证token和获取其中的信息: ```java public static Map<String, Claim> verifyToken(String token) throws Exception { JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build(); DecodedJWT jwt = verifier.verify(token); return jwt.getClaims(); } ``` 上面的代码会使用之前设置的密钥来验证token,并返回包含token中所有声明的Map。 这样,你就可以在Java使用JWT生成token了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [JWT介绍及用JAVA使用JWT生成token](https://blog.csdn.net/weixin_43085439/article/details/105838751)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值