JWT令牌(JSON Web Token)

目录

1 前言

2 JWT令牌的组成

3 使用步骤举例

3.1 pom.xml中引入依赖

3.2 JWT生成

3.3 JWT验证

4 实践中的使用举例

4.1 拦截非法访问

4.1.1 编写为工具类

4.1.2 下发给用户

4.1.3 编写拦截器

 4.1.4 注册拦截器

4.2 获取相关数据提升效率


1 前言

在我们编写的后端程序中,如果没有进行相关处理,那么就可能出现绕过登录,直接访问相关接口的情况。因此,我们引入了JWT令牌(一段特殊的字符串)。此外,使用JWT令牌,还要如下好处:

①减少查询数据库的次数,提高性能

②防止篡改,提高安全性

2 JWT令牌的组成

hdoj1u901jd.q0hd=kd.dhiwihdih(随便弄的,演示一下)

 以.为分隔,我们可以将JWT令牌拆解成三部分

第一部分(Header/头):记录令牌类型和签名算法等

第二部分(Payload/有效载荷):携带一些自定义信息,如:id和用户名,不宜包含密码。因为JWT是依赖于Base64生成的,而Base64只是一种编码方式而非加密,携带密码就不安全

第三部分(Signature/签名):防止篡改,确保安全性,由前两部分+秘钥通过加密算法得到

3 使用步骤举例

3.1 pom.xml中引入依赖


      com.auth0
      java-jwt
      4.4.0

3.2 JWT生成

public class JwtTest {
    @Test
    public void testGenerate() {
        Map claims = new HashMap<>();
        claims.put("id", 5);
        claims.put("username", "zy");
        //生成jwt的代码
        String token = JWT.create()
                .withClaim("user", claims)//添加载荷
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000*60*60*2))//添加过期时间
                .sign(Algorithm.HMAC256("test"));//指定算法,配置秘钥
        System.out.println(token);
    }
}

3.3 JWT验证

public class JwtTest {
    /**
     * JWT校验报错(失败)的两种情况:
     * 1.JWT被修改
     * 2.token过期
     */
    @Test
    public void testParse() {
        //testGenerate()生成的的字符串,模拟用户传递过来的token
        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" +
                ".eyJ1c2VyIjp7ImlkIjo1LCJ1c2VybmFtZSI6Inp5In0sImV4cCI6MTcwNjE3NjYxMX0" +
                ".bTpMAeawJ3u9-d2PKL2JIhynwGjTPZlkp1RIREwMDVc";
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("test")).build();

        DecodedJWT decodedJWT = jwtVerifier.verify(token);//验证token,生成一个解析后的JWT对象
        Map claims = decodedJWT.getClaims();//获得载荷
        System.out.println(claims.get("user"));
    }
}

4 实践中的使用举例

4.1 拦截非法访问

4.1.1 编写为工具类

public class JwtUtil {
    //自定义秘钥
    private static final String KEY = "XXXX";
	
	//接收业务数据,生成token并返回
    public static String genToken(Map claims) {
        return JWT.create()
                .withClaim("claims", claims)//添加载荷
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 ))//设置过期时间
                .sign(Algorithm.HMAC256(KEY));//选择加密算法
    }

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

}

4.1.2 下发给用户

@RestController
@RequestMapping("/user")
public class UserController {
    @PostMapping("/login")
    public Result login(String username, String password) {
            //其它代码...
            User loginUser = userService.findByUserName(username);
            Map claims = new HashMap<>();
            claims.put("id", loginUser.getId());
            claims.put("username", loginUser.getUsername());
            String token = JwtUtil.genToken(claims);
            return Result.success(token);
    }
    //其它代码...
}

4.1.3 编写拦截器

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            //xxx为约定好的请求头中携带的名称
            Map claims = JwtUtil.parseToken(request.getHeader("xxx"));
            //放行
            return true;
        } catch (Exception e) {
            response.setStatus(401);//约定好的状态码,一般401表示未授权
            //不放行
            return false;
        }
    }
}

 4.1.4 注册拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

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

大功告成,如果未登录访问接口,就会401。

4.2 获取相关数据提升效率

我们可以在请求头中获取有效载荷中的有效信息。

//token中包含id和username
public Result func(@RequestHeader(name = "XXX") String token) {
        Map map = JwtUtil.parseToken(token);
        String username = (String)map.get("username");
        User user = userService.findByUserName(username);
        return Result.success(user);
}

你可能感兴趣的:(SpringBoot,java,jwt,spring,boot,拦截器)