分布式应用的用户信息检验方案JWT


 

jwt简介

Json web token(JWT):使用HMAC或RSA算法加密用户信息生成token,存储在客户端(浏览器),客户端请求服务端时携带上token,服务端解密token获取用户信息。
 

优缺点

  • 优点:token包含了用户的id、昵称、头像等基本信息,避免了再次查库;使用json交换数据,通用、轻量;token存储在客户端,适合分布式应用、单点登录,不占用服务端的内存资源。
  • 缺点:token存储在客户端,获取到token后可直接使用他人身份进行操作,有一定的安全风险;尽量使用https协议,避免传输token到服务器时被他人窃取。
     

jwt的组成

  • header:头部,主要描述签名算法。
  • payload:负载,主要是加密的数据,也可以设置token过期时间等一些说明信息。payload中的数据可以被客户端解码,不要在token中存储密码、用户权限等敏感信息。
  • signature:签名,把header、payload进行加密,防止别人窃取token后进行解密篡改。

token使用2个小数点分隔这三部分。
 

支持多种加密算法,最常用的是 HMAC SHA256。

token可以存储在浏览器的Cookie、Local Storage、Session Storage中,一般存储在Cookie中。

jwt有多种实现方式,java常用的2种jwt实现类库是jjwt、java-jwt。

 

jjwt实现jwt

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
import com.example.demo.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

/**
 * JWT工具类
 */
public class JWTUtil {

    /**
     * token颁布方
     */
    public static final String ISSUER = "chy.com";


    /**
     * token过期时间,7天
     */
    private static final long EXPIRE = 1000 * 60 * 60 * 24 * 7;


    /**
     * 秘钥
     */
    public static final String SECRET = "chy.com";


    /**
     * token前缀
     */
    public static final String TOKEN_PREFIX = "chy";


    /**
     * 生成token
     */
    public static String generateToken(User user) {
        String token = Jwts.builder()
        		//用户信息
                .claim("id", user.getId())
                .claim("username", user.getUsername())
                .claim("head_img", user.getHeadImg())
                //token颁布方
                .setIssuer(ISSUER)
                //token颁发时间
                .setIssuedAt(new Date())
                //token过期时间
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                //签名算法、秘钥
                .signWith(SignatureAlgorithm.HS256, SECRET)
                .compact();
        //拼接前缀,可选
        return TOKEN_PREFIX + token;
    }


    /**
     * 解密token得到用户信息
     * 
     * Claims中包含了token中存储的数据,可通过get方法获取,返回值是Object
     * eg. String username = claims.get("username").toString();
     */
    public static Claims checkToken(String token) {
        try {
            final Claims claims = Jwts.parser().setSigningKey(SECRET)
                    .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                    .getBody();
            return claims;
        } catch (Exception e) {
            return null;
        }
    }


}

官方github地址:https://github.com/jwtk/jjwt

 

java-jwt实现jwt

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.13.0</version>
</dependency>
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.demo.entity.User;

import java.util.Date;

/**
 * JWT工具类
 */
public class JWTUtil {

    /**
     * token颁布方
     */
    public static final String ISSUER = "chy.com";


    /**
     * token过期时间,7天
     */
    private static final long EXPIRE = 1000 * 60 * 60 * 24 * 7;


    /**
     * 秘钥
     */
    public static final String SECRET = "chy.com";


    /**
     * token前缀
     */
    public static final String TOKEN_PREFIX = "chy";


    /**
     * 生成token
     */
    public static String generateToken(User user) {
        try {
            //签名算法、秘钥
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            String token = JWT.create()
                    //用户信息
                    .withClaim("id", user.getId())
                    .withClaim("username", user.getUsername())
                    .withClaim("head_img", user.getHeadImg())
                    //token颁布方
                    .withIssuer(ISSUER)
                    //token颁发时间
                    .withIssuedAt(new Date())
                    //token过期时间
                    .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRE))
                    .sign(algorithm);
            return token;
        } catch (JWTCreationException exception) {
            //Invalid Signing configuration | Couldn't convert Claims.
            return null;
        }
    }


    /**
     * 解密token得到用户信息
     * 
     * //获取token中所有的claim(封装的用户信息)
     * Map<String, Claim> claims = decodedJWT.getClaims();
     * //get()获取到的是Claim类型,需要用asXxx()转一下
     * String string = claims.get("username").asString();
     */
    public static DecodedJWT checkToken(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer(ISSUER)
                    .build();
            DecodedJWT decodedJWT = verifier.verify(token);
            return decodedJWT;
        } catch (JWTVerificationException exception) {
            //Invalid signature|claims
            return null;
        }
    }


}

官方github地址:https://github.com/auth0/java-jwt

 

说明

1、可以加入一些额外的加密操作,增加被被人破解的难度,比如拼接前缀、使用其它加密算法再次加密等。
 

2、用户登录成功后,后端生成token,可以由后端操作HttpServletResponse把token添加到cookie中;也可以直接把token传给前端,由前端添加到cookie中。不管哪种,都需要手动设置cookie的过期时间。
 

3、在网关拦截器处,从HttpServletRequest对象中解析token获取用户信息

String token = httpServletRequest.getHeader("token");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值