jjwtを用いてjwtを実現する

9769 ワード

背景紹介
プロジェクトではSpring Bootが使用する、マイクロサービスアーキテクチャであるため、現在はSessionを使用してユーザログイン状態(sessionはクッキーに基づいて実現される)状態を記憶したくない、JWTを選択してユーザIDを記憶し、アイデンティティ認証の証明書とする.
JWT紹介(Json Web Token)
Json web token(JWT)は、ネットワークアプリケーション環境間で宣言を伝達するために実行されるJSONベースのオープンスタンダード(RFC 7519)である.このtokenは、コンパクトで安全に設計され、特に分散サイトの単一のログインシーンに適している.JWTの宣言は、一般に、リソースサーバからリソースを取得するために認証されたユーザ識別情報をアイデンティティプロバイダとサービスプロバイダとの間で伝達するために使用され、追加の他のビジネスロジックに必要な宣言情報を追加することもでき、tokenは直接認証に使用され、暗号化されてもよい.
JWT構成
jwt      :  (header),  (payload),  (signature),    
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIxIiwibmJmIjoxNTE3OTEzMzY3LCJleHAiOjE1MTc5MTMzNzd9.9QTvNWuwJsma84AfeXK4JO9ozOy4owmZJws9IZ2DMAI

ヘッド
{
    'typ':'JWT',
    'alg':'HS256',
}
        ,
typ:  
alg:    

ヘッダをBase 64で暗号化し、
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

荷重(payload)
有効な情報を格納する場所は、一般的に3つの部分から構成されています.
1.標準に登録されている宣言(強制しない)
iss: jwt   
sub: jwt      
aud:   jwt   
exp: jwt     ,               
nbf:          , jwt      .
iat: jwt     
jti: jwt       ,         token,        

2.共通の声明
公共情報を保管する場所
3.私有声明
私有情報を保管する場所
注意:荷重に機密情報を格納しない
以下に使用する荷重
{
    'nbf':'Tue Feb 06 18:36:07 CST 2018',
    'exp':'Tue Feb 06 18:36:17 CST 2018',
    'userId':'1'
}

キャリアをBase 64で暗号化し、
eyJ1c2VySWQiOiIxIiwibmJmIjoxNTE3OTEzMzY3LCJleHAiOjE1MTc5MTMzNzd9

署名(signature)
得られたヘッダと荷重を暗号化した文字列をつなぎ合わせ,ヘッダにalgが指定した暗号化アルゴリズムを用いてsecret塩を加えて暗号化し,得られた
9QTvNWuwJsma84AfeXK4JO9ozOy4owmZJws9IZ2DMAI

最後に3つの部分を'.'でつなぎ合わせるといいです
使用方法
ユーザーがログインして検証に合格すると、jwtがフロントエンドに返され、フロントエンドはリクエストヘッダに「Authorization」フィールドを追加し、リクエストごとにこのリクエストヘッダを持ち込み、バックエンドはuserIdに基づいてユーザーIDを判断する
具体的に実現する
プロジェクトで使用するjjwtはpom.xmlに以下の依存性を導入する


	io.jsonwebtoken
	jjwt
	0.7.0
	compile


プロジェクトの構成は以下の通りです.
jwt
 |_ excption
         |_JwtParameterEmptyException.java
         |_JwtParameterIllegalException.java
 |_jwtInfo.java
 |_JwtPayload.java
 |_JwtUtils.java


ここでexceptionパッケージの下にはカスタム例外があります
JwtInfo.javaコードは次の通りです.
package com.liao.common.jwt;

/**
 * Jwt  (  Jwt       )
 *
 * @author hongyangliao
 * @ClassName: JwtInfo
 * @Date 17-12-28   3:42
 */
public class JwtInfo extends JwtPayload {
    /**
     *        
     *     : HS256
     */
    private String alg;

    /**
     *     
     */
    private String secret;

    /**
     *          
     */
    private long expiresMillis;

    /**
     *    token  
     */
    private String token;

    public String getAlg() {
        return alg;
    }

    public void setAlg(String alg) {
        this.alg = alg;
    }

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public long getExpiresMillis() {
        return expiresMillis;
    }

    public void setExpiresMillis(long expiresMillis) {
        this.expiresMillis = expiresMillis;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    @Override
    public String toString() {
        return "JwtInfo{" +
                "alg='" + alg + '\'' +
                ", secret='" + secret + '\'' +
                ", expiresMillis=" + expiresMillis +
                ", token='" + token + '\'' +
                '}';
    }
}


JwtPayload.javaコードは次の通りです.
package com.liao.common.jwt;

import java.util.Date;

/***
 * Jwt  
 *
 * @ClassName: JwtPayload
 * @author hongyangliao
 * @Date 17-12-28   2:34
 */
public class JwtPayload {
    /**
     *   id
     */
    private String userId;

    /**
     *     
     */
    private Date exp;

    /**
     *            
     */
    private Date nbf;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public Date getExp() {
        return exp;
    }

    public void setExp(Date exp) {
        this.exp = exp;
    }

    public Date getNbf() {
        return nbf;
    }

    public void setNbf(Date nbf) {
        this.nbf = nbf;
    }

    @Override
    public String toString() {
        return "JwtPayload{" +
                "userId='" + userId + '\'' +
                ", exp=" + exp +
                ", nbf=" + nbf +
                '}';
    }
}

JwtUtils.javaコードは次のとおりです.
package com.liao.common.jwt;

import com.liao.common.jwt.exception.JwtParameterEmptyException;
import com.liao.common.jwt.exception.JwtParameterIllegalException;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;


/***
 * Jwt   (  jjwt)
 *
 * @ClassName: JwtUtils
 * @author hongyangliao
 * @Date 17-12-28   6:16
 */
public class JwtUtils {
    /***
     *   Jwt
     *
     * @Title: generateJwt
     * @author: hongyangliao
     * @Date: 17-12-28   4:38
     * @param jwtInfo jwt        alg,userId,secret,expiresMillis
     * @return java.lang.String
     * @throws
     */
    public static String generateJwt(JwtInfo jwtInfo) throws JwtParameterEmptyException, JwtParameterIllegalException, SignatureException {
        if (jwtInfo == null) {
            throw new JwtParameterEmptyException("Jwt      ");
        }

        //    
        String alg = jwtInfo.getAlg();
        String userId = jwtInfo.getUserId();
        String secret = jwtInfo.getSecret();
        long expiresMillis = jwtInfo.getExpiresMillis();

        if (StringUtils.isBlank(alg) || StringUtils.isBlank(userId) || StringUtils.isBlank(secret)) {
            throw new JwtParameterEmptyException("Jwt      ");
        }

        if (expiresMillis < 0) {
            throw new JwtParameterIllegalException("       ");
        }

        Date currentDate = new Date();
        long dateMillis = currentDate.getTime() + expiresMillis;
        Date date = new Date(dateMillis);

        //  jwtInfo.getAlg()      SignatureException
        SignatureAlgorithm signatureAlgorithm = null;
        try {
            signatureAlgorithm = SignatureAlgorithm.forName(jwtInfo.getAlg());
        } catch (SignatureException e) {
            throw new SignatureException("(alg)         ");
        }

        String token = null;
        if (signatureAlgorithm != null) {
            //    ,  ,  
            token = Jwts.builder()
                    .setHeaderParam("typ", "JWT")
                    .setHeaderParam("alg", jwtInfo.getAlg())
                    .claim("userId", jwtInfo.getUserId())
                    .setNotBefore(currentDate)
                    .setExpiration(date)
                    .signWith(signatureAlgorithm, secret)
                    .compact();
        }
        return token;
    }

    /***
     *        Jwt  
     *
     * @Title: getJwtPayload
     * @author: hongyangliao
     * @Date: 17-12-28   4:59
     * @param jwtInfo jwt  ,     token,secret
     * @return com.ducetech.common.jwt.JwtPayload Jwt  
     * @throws
     */
    public static JwtPayload getJwtPayload(JwtInfo jwtInfo)
            throws JwtParameterEmptyException, ExpiredJwtException,
            UnsupportedJwtException, MalformedJwtException,
            SignatureException, IllegalArgumentException {
        //    
        if (jwtInfo == null) {
            throw new JwtParameterEmptyException("Jwt      ");
        }

        String secret = jwtInfo.getSecret();
        String token = jwtInfo.getToken();

        if (StringUtils.isBlank(secret) || StringUtils.isBlank(token)) {
            throw new JwtParameterEmptyException("Jwt      ");
        }

        Jws jws = null;
        try {
            jws = Jwts.parser().setSigningKey(jwtInfo.getSecret()).parseClaimsJws(jwtInfo.getToken());
        } catch (ExpiredJwtException ee) {
            //token   
            throw ee;
        } catch (UnsupportedJwtException ujw) {
            //       
            throw ujw;
        } catch (MalformedJwtException mje) {
            //    
            throw mje;
        } catch (SignatureException se) {
            //jwt     
            throw se;
        } catch (IllegalArgumentException iae) {
            //       
            throw iae;
        }

        JwtPayload jwtPayload = new JwtPayload();
        if (jws != null) {
            Claims claims = jws.getBody();
            String userId = claims.get("userId", String.class);
            jwtPayload.setUserId(userId);
            jwtPayload.setExp(claims.getExpiration());
            jwtPayload.setNbf(claims.getNotBefore());
        }
        return jwtPayload;
    }

    public static void main(String[] args) {
        JwtInfo jwtInfo = new JwtInfo();
        jwtInfo.setAlg("HS256");
        jwtInfo.setUserId("1");
        jwtInfo.setSecret("hongyangliao");
        jwtInfo.setExpiresMillis(10000L);
        String jwt = generateJwt(jwtInfo);
        System.out.println(jwt);
        jwtInfo.setToken(jwt);
        JwtPayload jwtPayload = getJwtPayload(jwtInfo);
        System.out.println(jwtPayload);
    }
}

リファレンス
JWT–JSON WEB TOKENとは