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;
        }
    }
}
相关文章
相关标签/搜索