zoukankan      html  css  js  c++  java
  • 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;
            }
        }
    }

      

  • 相关阅读:
    Spring MVC 下index.jsp访问
    Spring MVC的UrlBasedViewResolver和InternalResourceViewResolver
    js中encode、decode的应用说明
    Spring3.1新特性介绍
    Spring MVC定义拦截器
    Spring 使用注解方式进行事务管理
    GET,POST,PUT,DELETE的区别
    SpringMVC注解@RequestParam全面解析
    java实现DES算法
    程序员要考虑的事
  • 原文地址:https://www.cnblogs.com/xiaoSY-learning/p/6835748.html
Copyright © 2011-2022 走看看