JWT 登录

token认证

随着 Restful API、微服务的兴起,基于 token 的认证现在已经越来越普遍。基于token的用户认证是一种服务端无状态的认证方式,所谓服务端无状态指的token本身包含登录用户所有的相关数据,而客户端在认证后的每次请求都会携带token,因此服务器端无需存放token数据。

​ 当用户认证后,服务端生成一个token发给客户端,客户端可以放到 cookie 或 localStorage 等存储中,每次请求时带上 token,服务端收到token通过验证后即可确认用户身份。

在这里插入图片描述

什么是JWT?

​ 我们现在了解了基于token认证的交互机制,但令牌里面究竟是什么内容?什么格式呢?市面上基于token的认证方式大都采用的是JWT(Json Web Token)。

​ JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。

JWT令牌结构:

JWT令牌由Header、Payload、Signature三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz

  • Header

头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC、SHA256或RSA)。

一个例子:

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

将上边的内容使用Base64编码,得到一个字符串就是JWT令牌的第一部分。

  • Payload

第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比
如:iss(签发者),exp(过期时间戳), sub(面向的用户)等,也可自定义字段。
此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。
一个例子:

{
	"sub": "1234567890""name": "456""admin": true
}

最后将第二部分负载使用Base64编码,得到一个字符串就是JWT令牌的第二部分。

  • Signature

第三部分是签名,此部分用于防止jwt内容被篡改。
这个部分使用base64将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明
签名算法进行签名。
一个例子:

HMACSHA256(  base64UrlEncode(header) + "." +  base64UrlEncode(payload),secret)

使用jwt生成token

  1. 引入依赖
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
</dependency>
  1. 封装jjwt的的工具类
import com.heima.common.dtos.Payload;
import io.jsonwebtoken.*;
import org.joda.time.DateTime;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;

/**
 * JWT 工具类
 * 对JJWT的封装
 */
public class JwtUtils {

    private static final String JWT_PAYLOAD_USER_KEY = "id";
    // 加密KEY
    private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";

    /**
     * 加密token
     *
     * @param userId 载荷中的数据
     * @param expire 过期时间,单位分钟
     * @return JWT
     */
    public static String generateTokenExpireInMinutes(Integer userId, int expire) {
        Map<String, Object> claimMaps = new HashMap<>();
        claimMaps.put(JWT_PAYLOAD_USER_KEY,userId);
        return Jwts.builder()
                .addClaims(claimMaps)
                .setId(createJTI())
                .setExpiration(DateTime.now().plusMinutes(expire).toDate())
                .compressWith(CompressionCodecs.GZIP)  //数据压缩方式
                .setIssuedAt(new Date(System.currentTimeMillis()))  //签发时间
                .setSubject("system")  //说明
                .setIssuer("heima") //签发者信息
                .setAudience("app")  //接收用户
                .signWith(SignatureAlgorithm.HS256, generalKey())
                .compact();
    }

    /**
     * 由字符串生成加密key
     *
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 加密token
     *
     * @param userId 载荷中的数据
     * @param expire 过期时间,单位秒
     * @return JWT
     */
    public static String generateTokenExpireInSeconds(Integer userId, int expire) {
        Map<String, Object> claimMaps = new HashMap<>();
        claimMaps.put(JWT_PAYLOAD_USER_KEY,userId);
        return Jwts.builder()
                .addClaims(claimMaps)
                .setId(createJTI())
                .setExpiration(DateTime.now().plusSeconds(expire).toDate())
                .compressWith(CompressionCodecs.GZIP)  //数据压缩方式
                .setIssuedAt(new Date(System.currentTimeMillis()))  //签发时间
                .setSubject("system")  //说明
                .setIssuer("heima") //签发者信息
                .setAudience("app")  //接收用户
                .signWith(SignatureAlgorithm.HS256, generalKey())
                .compact();
    }

    /**
     * 解析token
     *
     * @param token 用户请求中的token
     * @return Jws<Claims>
     */
    private static Jws<Claims> parserToken(String token) {
        return Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(token);
    }

    private static String createJTI() {
        return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));
    }

    /**
     * 获取token中的用户信息
     *
     * @param token 用户请求中的令牌
     * @return 用户信息
     */
    public static Payload getInfoFromToken(String token) {
        Jws<Claims> claimsJws = parserToken(token);
        Claims body = claimsJws.getBody();
        Payload claims = new Payload();
        claims.setId(body.getId());
        claims.setUserId(Integer.valueOf(body.get(JWT_PAYLOAD_USER_KEY).toString()));
        claims.setExpiration(body.getExpiration());
        return claims;
    }

}
  1. 生成token,解析token
    public static void main(String[] args) {
        //生成token
        String token = JwtUtils.generateTokenExpireInMinutes(209617, 30);
        System.out.println("生成的token:\n" + token);

        //解析token
        try {
            Payload payload = JwtUtils.getInfoFromToken(token);
            System.out.println("解析后的payload内容为:\n" + payload);
        } catch (Exception e) {
            System.out.println("解析token失败");
            e.printStackTrace();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值