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中引入依赖

<dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>4.4.0</version>
</dependency>

3.2 JWT生成

public class JwtTest {
    @Test
    public void testGenerate() {
        Map<String, Object> 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<String, Claim> 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<String, Object> claims) {
        return JWT.create()
                .withClaim("claims", claims)//添加载荷
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 ))//设置过期时间
                .sign(Algorithm.HMAC256(KEY));//选择加密算法
    }

	//接收token,验证token,并返回业务数据
    public static Map<String, Object> 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<String> login(String username, String password) {
            //其它代码...
            User loginUser = userService.findByUserName(username);
            Map<String, Object> 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<String, Object> 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<User> func(@RequestHeader(name = "XXX") String token) {
        Map<String, Object> map = JwtUtil.parseToken(token);
        String username = (String)map.get("username");
        User user = userService.findByUserName(username);
        return Result.success(user);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厂里英才

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值