java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java中的JWT

Java中的JWT使用详解

作者:一支有理想的月月鸟

这篇文章主要介绍了Java中的JWT使用详解,JWT是一个开放标准(rfc7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全地传输信息,需要的朋友可以参考下

JWT

JSON Web Token(JSON Web令牌)

是一个开放标准(rfc7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全地传输信息。此信息可以验证和信任,因为它是数字签名的。

jwt可以使用秘密〈使用HNAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

通过JSON形式作为Web应用中的令牌,用于在各方之间安全地将信息作为JSON对象传输。在数据传输过程中还可以完成数据加密、签名等相关处理。

JWT作用:

1.传统Session

1.1.认证方式

http协议本身是一种无状态的协议,如果用户向服务器提供了用户名和密码来进行用户认证,下次请求时,用户还要再一次进行用户认证才行。

因为根据http协议,服务器并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储─份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样应用就能识别请求来自哪个用户。

1.2.暴露的问题

2.JWT认证

2.1.认证流程

2.2.JWT优点

3.JWT结构

就是令牌token,是一个String字符串,由3部分组成,中间用点隔开

令牌组成:

  1. 标头(Header)
  2. 有效载荷(Payload)
  3. 签名(Signature)

token格式:head.payload.singurater 如:xxxxx.yyyy.zzzz

{
	"alg" : "HS256",
	"type" : "JWT"
}
{
	"sub" : "123",
	"name" : "John Do",
	"admin" : true
}
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);

**签名目的:**签名的过程实际上是对头部以及负载内容进行签名,防止内容被窜改。如果有人对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务器端会判断出新的头部和负载形成的签名和JWT附带上的签名是不一样的。如果要对新的头部和负载进行签名,在不知道服务器加密时用的密钥的话,得出来的签名也是不一样的。

信息安全问题:Base64是一种编码,是可逆的,适合传递一些非敏感信息;JWT中不应该在负载中加入敏感的数据。如传输用户的ID被知道也是安全的,如密码不能放在JWT中;JWT常用于设计用户认证、授权系统、web的单点登录。

4.JWT使用

4.1.引入依赖

<!--引入JWT-->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.0</version>
</dependency>

4.2.生成token

HashMap<String,Object> map = new HashMap<>();
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND,20);
        String token = JWT.create()
                .withHeader(map) //可以不设定,就是使用默认的
                .withClaim("userId",20)//payload  //自定义用户名
                .withClaim("username","zhangsan")
                .withExpiresAt(instance.getTime()) //指定令牌过期时间
                .sign(Algorithm.HMAC256("fdahuifeuw78921"));//签名

4.3.根据令牌和签名解析数据

JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("fdahuif921")).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        decodedJWT.getClaim("userId").asInt();//获取负载里面对应的内容
        decodedJWT.getClaim("username").asString();
        decodedJWT.getExpiresAt();//获取过期时间

4.4.常见异常信息

SignatureVerificationException //签名不一致异常
TokenExpiredException //令牌过期异常
AlgorithmMismatchException //算法不匹配异常
InvalidClaimException //失效的payload异常(传给客户端后,token被改动,验证不一致)

5.封装工具类

public class JWTUtils {
    private static String SIGNATURE = "token!@#$%^7890";
    /**
     * 生成token
     * @param map //传入payload
     * @return 返回token
     */
    public static String getToken(Map<String,String> map){
        JWTCreator.Builder builder = JWT.create();
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND,7);
        builder.withExpiresAt(instance.getTime());
        return builder.sign(Algorithm.HMAC256(SIGNATURE)).toString();
    }
    /**
     * 验证token
     * @param token
     */
    public static void verify(String token){
        JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
    }
    /**
     * 获取token中payload
     * @param token
     * @return
     */
    public static DecodedJWT getToken(String token){
        return JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
    }
}

6.SpringBoot整合JWT

6.1.登录时生成token

//controller层接收数据,生成token,并响应
Map<String,Object> map = new HashMap<>();
try{
    User userDB = userService.login(user);
    Map<String,String> payload = new HashMap<>();
    payload.put("id",userDB.getId());
    payload.put("name",userDB.getName());
    //生成JWT令牌
    String token = JWTUtils.getToken(payload);
    map.put("state",true);
    map.put("msg","认证成功");
    map.put("token",token);//响应token
} catch (Exception e) {
    map.put("state","false");
    map.put("msg",e.getMessage());
}

6.2.声明一个token拦截器类

package com.liup.interceptor;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.office.utils.JWTUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
 * JWT验证拦截器
 */
public class JWTInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map<String,Object> map = new HashMap<>();
        //令牌建议是放在请求头中,获取请求头中令牌
        String token = request.getHeader("token");
        try{
            JWTUtils.verify(token);//验证令牌
            return true;//放行请求
        } catch (SignatureVerificationException e) {
            e.printStackTrace();
            map.put("msg","无效签名");
        } catch (TokenExpiredException e) {
            e.printStackTrace();
            map.put("msg","token过期");
        } catch (AlgorithmMismatchException e) {
            e.printStackTrace();
            map.put("msg","token算法不一致");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("msg","token失效");
        }
        map.put("state",false);//设置状态
        //将map转化成json,response使用的是Jackson
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().print(json);
        return false;
    }
}

6.3.配置拦截器

package com.liup.config;
import com.office.interceptor.JWTInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/user/**");
    }
}

到此这篇关于Java中的JWT使用详解的文章就介绍到这了,更多相关Java中的JWT内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文