jwt生成token

SSO服務

 1、流程java

  一、用戶登陸統一認證系統(uums)web

  二、uums判斷登陸是否有效算法

  有效:生成token,並帶生成的token返回給用戶數據庫

  無效:返回登陸頁面從新登陸json

  三、用戶登陸uums子系統,uums對請求進行攔截,判斷token是否有效api

  有效:正常訪問安全

  無效:返回從新登陸 401(未受權)cookie

2、token生成工具

  JWT(JSON WEB TOKEN) 加密字符串:BASE64+HS256算法post

  第一步:頭部信息 BASE64 (A)

  第二步:載荷信息 BASE64 (B)

  第三步:(A+B) HS256算法 (C)

  第四部: JWT = A+B+C

3、token驗證

  一、客戶端發出請求(get、post、api、頁面)

  二、uums對請求進行攔截

  三、判斷須要驗證token

  四、查找token

    a.cookie中查找是否存在token

    b.HTTP Authorization Head中查找是否存在token

  五、驗證token

    a.經過配置文件取祕鑰,對JWT進行解密解碼

    b.驗證簽名、載荷信息中的exp等信息

  六、取用戶權限、角色信息,進行角色判斷

4、token總結

  一、token是個信息集合

  二、token中信息要足夠的,以便減小對數據庫的訪問

  三、token對cookie和HTTP Authorization Head進行檢查

  四、token簽名需可解碼 及 信息的有效性

package com.tonbusoft.uums.commons.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import com.tonbusoft.uums.commons.ConfigBean;
import com.tonbusoft.uums.module.ua.bean.UaUser;

/**
 * token工具類 JWT
 */
public class JWTUtils {
    /**
     * 生成token
     * @param id tokenId
     * @param issuer 簽發者 UUMS
     * @param subject 面向用戶 tongyi
     * @param nowMillis token生成時間 long
     * @param ttlMillis token生成後多久過時 long
     * @param user 生成token的用戶信息
     * @param ip 請求登陸IP地址
     * @return
     */
    public static String createToken(String id, String issuer, String subject,
            long nowMillis, long ttlMillis, UaUser user, String ip) {
        // JWT簽名算法 用HS256加密
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 當前時間
//        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        // 進行加密用的祕鑰
        byte[] apiKeySecretBytes = DatatypeConverter
                .parseBase64Binary(ConfigBean.tokenSecret);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes,
                signatureAlgorithm.getJcaName());
        // 設置JWT Claims
        // 用簽名算法HS256和私鑰key生成token
        JwtBuilder builder = Jwts.builder().setId(id)// 版本號
                .setIssuedAt(now)// 什麼時候簽發 時間戳 設置如今時間
                                    // 它能夠用來作一些maxAge之類的驗證,假如驗證時間與這個claim指定的時間相差的時間大於經過maxAge指定的一個值,就屬於驗證失敗
                .setSubject(subject)// 面向用戶 抽象主題
                .setIssuer(issuer)// 簽發者
//                .setAudience("")//設置角色  ['b.com','c.com']驗證的時候這個claim的值至少要包含b.com,c.com的其中一個才能驗證經過;
                .claim("user", user)
                .claim("ip", ip)
                .signWith(signatureAlgorithm, signingKey); // 加密方法
        // 設置失效時間
//        Date exp = null;
//        if (ttlMillis >= 0) {
//            long expMillis = nowMillis + ttlMillis;
//            exp = new Date(expMillis);
//            builder.setExpiration(exp);// 過時時間
//        }
        // 設置序列化 URL安全化
        String tokenString = builder.compact();
        return tokenString;
    }

    /**
     * 刷新獲取token
     * @param oldToken 以前舊的token
     * @return
     */
    public static String refreshToken(String oldToken) {
        String newToken = "";
        // 解密舊token
        // 驗證簽名
        Claims claims = Jwts.parser() // 返回配置實例化後的實例
                .setSigningKey(DatatypeConverter.parseBase64Binary(ConfigBean.tokenSecret)) // 根據配置文件中的祕鑰進行解密
                .parseClaimsJws(oldToken).getBody(); // 獲取JWT中的載荷
        // 獲取相關信息
        // 面向用戶
        String subject = claims.getSubject();
        // 簽發者
        String issuer = claims.getIssuer();
        // IP地址
        String ip = claims.get("ip").toString();
        // 用戶信息
        UaUser user = claims.get("user", UaUser.class);
        
        long nowMillis = System.currentTimeMillis();
        long ttlMillis = 3600000;
        // 生成新token
        newToken = createToken("1", issuer, subject, nowMillis, ttlMillis, user, ip);
        return newToken;
    }
    
    //解密token
    public static Claims parseJWT(String token){
        return Jwts.parser()   //返回配置實例化後的實例     
                   .setSigningKey(DatatypeConverter.parseBase64Binary(ConfigBean.tokenSecret)) //根據配置文件中的祕鑰進行解密
                   .parseClaimsJws(token)
                   .getBody(); 
    }
    
    /**
     * 驗證token
     * @param claims token解密後的信息集合
     * @return
     */
    public static Map<String, Object> validateToken (Claims claims, String Ip) {
        Map<String, Object> result = new HashMap<String, Object>();
        String jwtId = claims.getId();
        //面向用戶
        String subject = claims.getSubject(); 
        //簽發者
        String issuer = claims.getIssuer();
        //什麼時候簽發
        Date issuedAt = claims.getIssuedAt();
        //IP
        Object ip = claims.get("ip");
//        UaUser user = claims.get("user", UaUser.class);
        
        //驗證一 jwtId是否爲1
        if (!"1".equals(jwtId)) {
            System.out.println("token序列不爲1 token驗證不經過");
            result.put("code", 1);
            result.put("flag", false);
            result.put("msg", "token 無效");
        } else if (!"UUMS".equals(issuer)) {
            //驗證二 簽發者是不是UUMS
            System.out.println("簽發者不是UUMS token驗證不經過");
            result.put("code", 2);
            result.put("flag", false);
            result.put("msg", "token 無效");
        } else if (null == subject) {
            //驗證三 面向用戶是不是當前用戶
            System.out.println("當前用戶爲空 token驗證不經過");
            result.put("code", 3);
            result.put("flag", false);
            result.put("msg", "token 無效");
        } else if (null ==ip) {
            //驗證四  當前用戶IP
            System.out.println("當前用戶IP異常 token驗證不經過");
            result.put("code", 4);
            result.put("flag", false);
            result.put("msg", "token 無效");
        } else if (!Ip.equals(ip.toString())) {
            //驗證四  當前用戶IP
            System.out.println("當前用戶IP異常 token驗證不經過");
            result.put("code", 4);
            result.put("flag", false);
            result.put("msg", "token 無效");
        }
        if (null != claims.get("user")) {
            //用戶信息
            String user = claims.get("user").toString();
            String temp = user.substring(user.indexOf("xl="));
            String[] s = temp.substring(0, temp.indexOf(",")).split("=");
            String zhxl = s[1];
            
            HashMap<String,Object> tokenInfo = ApplicationCache.getTokeninfo();
//            Integer zhxl = user.getXl();
            //經過帳戶序列獲取帳戶的過時時間
            Long gqsj =(Long)tokenInfo.get(zhxl);
            //獲取當前時間
            Long nowMillis = System.currentTimeMillis();
            if (gqsj <= nowMillis) {
                gqsj += 3600000;
                tokenInfo.put(zhxl.toString(), gqsj);
                ApplicationCache.setTokenInfo(tokenInfo);
            }
            result.put("code", 0);
            result.put("flag", true);
            result.put("msg", "token 驗證經過");
        } else {
            result.put("code", 4);
            result.put("flag", false);
            result.put("msg", "token 無效");
        }
        
        return result;
    }

    //驗證token
    private boolean validateToken(HttpServletRequest request, HttpServletResponse response) {
        //獲取token
        Map<String, Object> result = null;
        boolean tokenFlag = false;
        String token = null;
        String authHeader = request.getHeader("Authorization");
        if (null == authHeader || !authHeader.startsWith("Bearer ")) {
        } else {
            //截取掉Bearer 字符串
            token = authHeader.substring(7);
        }
        if (null != token) {
            //驗證token
            result = JWTUtils.validateToken(JWTUtils.parseJWT(token), IpUtil.getOuterIp(request));
            tokenFlag = (boolean)result.get("flag");
        }
        //token驗證成功 若是過時但仍需操做 則默認刷新token 沒必要重寫登陸
        if (tokenFlag) {
            response.setHeader("Authorization", "Bearer " + token);
            //token驗證成功
            return true;
        } else {
            //token驗證失敗
            return false;
        }
    }
}
相關文章
相關標籤/搜索