jwt生成token

SSO服务

 一、流程

  1、用户登录统一认证系统(uums)

  2、uums判断登录是否有效

  有效:生成token,并带生成的token返回给用户

  无效:返回登录页面重新登录

  3、用户登录uums子系统,uums对请求进行拦截,判断token是否有效

  有效:正常访问

  无效:返回重新登录 401(未授权)

二、token生成

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

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

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

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

  第四部: JWT = A+B+C

三、token验证

  1、客户端发出请求(get、post、api、页面)

  2、uums对请求进行拦截

  3、判断需要验证token

  4、查找token

    a.cookie中查找是否存在token

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

  5、验证token

    a.通过配置文件取秘钥,对JWT进行解密解码

    b.验证签名、载荷信息中的exp等信息

  6、取用户权限、角色信息,进行角色判断

四、token总结

  1、token是个信息集合

  2、token中信息要足够的,以便减少对数据库的访问

  3、token对cookie和HTTP Authorization Head进行检查

  4、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;
        }
    }
}

 

  

posted on 2017-05-10 14:17  晓怂样  阅读(1330)  评论(0编辑  收藏  举报

导航