• JWT(Json web token)认证详解


    JWT的定义:

      JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

    JWT特点:
      简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快
      自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库

    JWT结构:

    JWT主要包含Header 头部  Payload 负载  Signature 签名,顺序是 header.payload.signature 三部分之间用英语句号’.'隔开  
     

    Header头部

    头部包含了两部分,token 类型(“JWT”)和采用的加密算法(HMAC SHA256或者RSA等等)

    例如:

    然后,用Base64对这个JSON编码就得到JWT的第一部分

    Payload负载

    这部分就是我们存放信息的地方了,你可以把用户 ID 等信息放在这里,JWT 规范里面对这部分有进行了比较详细的介绍,常用的由 iss(签发者),exp(过期时间),sub(面向的用户),aud(接收方),iat(签发时间)。

    同样的,它会使用 Base64 编码组成 JWT 结构的第二部分。

    Signature签名

      前面两部分都是使用 Base64 进行编码的,即前端可以解开知道里面的信息。Signature 需要使用Base64编码后的 header 和 payload 以及我们提供的一个密钥,然后使用 header 中指定的签名算法(HS256)进行签名。签名的作用是保证 JWT 没有被篡改过。三个部分通过.连接在一起就是我们的 JWT 了,它可能长这个样子,长度貌似和你的加密算法和私钥有关系。

    eyJhbGciOiJIUzI1NiIsIlR5cGUiOiJKd3QiLCJ0eXAiOiJKV1QifQ.eyJsb2dpblRpbWUiOiIyMDIxLTEwLTI3VDE1OjIxOjU4LjU3OCIsInVzZXJOYW1lIjoi5rGf5Y2XIiwiZXhwIjoxNjM1MzIxMTE4fQ.lUojZpIGx0a65s5FrgYlQio0vf3jOuqWOTP-DUjzGh0
    注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了

    JSON Web Tokens是如何工作的?

    一般是在请求头里加入Authorization,并加上Bearer标注:

    fetch('api/user/1', {
      headers: {
        'Authorization': 'Bearer ' + token
      }
    })
    

    服务端会验证token,如果验证通过就会返回相应的资源。整个流程就是这样的:

    优点

    • 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
    • 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
    • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
    • 它不需要在服务端保存会话信息, 所以它易于应用的扩展

    安全相关

    • 不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
    • 保护好secret私钥,该私钥非常重要。
    • 如果可以,请使用https协议

    最后附上Token工具类

    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.JWTDecodeException;
    import com.auth0.jwt.interfaces.DecodedJWT;
    import java.time.LocalDateTime;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    public class TokenUtil {
    
        /**
         * token过期时间
         */
        private static final long EXPIRE_TIME = 30 * 60 * 1000;
        /**
         * token秘钥
         */
        private static final String TOKEN_SECRET = "secret";
    
    
        /**
         * 生成token,30分钟过期
         *
         * @param userName  用户名
         * @param loginTime 登录时间
         * @return 生成的token
         */
        public static String sign(String userName, LocalDateTime loginTime) {
            try {
                // 设置过期时间
                Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
                System.out.println(date);
                // 私钥和加密算法
                Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
                // 设置头部信息
                Map<String, Object> header = new HashMap<>(3);
                header.put("Type", "Jwt");
                header.put("alg", "HS256");
                // 返回token字符串
                return JWT.create()
                        .withHeader(header)
                        // 设置token中需要加载的用户信息 存储自己想要留给前端的内容
                        .withClaim("userName", userName)
                        .withClaim("loginTime", loginTime.toString())
                        .withExpiresAt(date)
                        .sign(algorithm);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * 检验token是否正确
         */
        public static boolean verify(String token) {
            try {
                //设置签名的加密算法:HMAC256
                Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
                JWTVerifier verifier = JWT.require(algorithm).build();
                verifier.verify(token);
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    
        /**
         * 获取token中信息 userName
         */
    
        public static String getUsername(String token) {
            try {
                DecodedJWT jwt = JWT.decode(token);
                return jwt.getClaim("userName").asString();
    
            } catch (JWTDecodeException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    我话讲完!谁赞成?谁反对?
  • 相关阅读:
    git升级
    redis集群
    redis安装
    escript
    git搭建仓库与服务器
    svnsync
    post_commit.sh
    nvm安装和使用
    quartz 定时器
    Oracle flashback恢复误删的数据或表
  • 原文地址:https://www.cnblogs.com/wffzk/p/15471800.html
Copyright © 2020-2023  润新知