SpringBoot 2.x 使用 JWT(JSON Web Token)

One of the problems encountered by cross-domain authentication

Due to the emergence of multiple terminals, through many sites web api restfulin the form of external services, using a model developed around the end of the separation, which may be related to traditional authentication based on the way cookiethe Session Iddifferent approaches, in addition to facing the cross-domain submit cookiea outside the problem, more importantly, some terminals might not support cookie.

JWT(JSON Web Token)Is an authentication and authorization scheme, simply means that the call to end calls apiwhen on comes a by the apiissuing side token, in order to verify the caller's authorization information.

The general process is this:

1. 用户向服务器发送用户名和密码。
2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3. 服务器向用户返回一个 session_id,写入用户的 Cookie。
4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

The problem with this model is that poor scalability. There is no single problem, if it is a cluster of servers, cross-domain service-oriented architecture or disabled by the user cookie, to die.

Second, the solution

1. Stand-alone and distributed applications at login check, session sharing

  • Single and multi-node tomcatapplication logon test

    ①, stand-alone tomcatapplication login, sesssionsaving between the browser and the application server session, after the user logs in successfully, the server will ensure that a sessionwill for a client sessionId, the client will sessionIdsave cookieeach time the user requests will carry this sessionId.

    ②, multi-node tomcatapplication login, open sessionafter data sharing, each server can read session. The disadvantage is that each sessionis take up memory and resources, each server node requires synchronization of user data, that is a need to store multiple copies of data to each server, when the user reaches the amount of millions-level resource occupation it is serious, the user experience is particularly bad! !

  • Distributed applications sessionshare

    ①, a real application can not single-node deployment, so there is more than one node login sessionproblems to be solved shared. tomcatSupport for sessionsharing, but there are broadcast storm; the user a large amount of time, resource-intensive to severe, is not recommended

    ②, Reidsclusters, storage landing tokenoutwardly service interface Rediscan set the expiration time (using the server UUIDgenerates a random 64bit or 128bits token, into Redis, and then returned to the client and stored).

    ③, the first time a user logs on successfully, you need to self-generate token, and then tokenreturned to the browser and stored cookiein,
    and Redison the server tokenas the keyuser information as the valuesave. Then subsequent user operation, can HttpServletRequestdirectly read the object cookieis token, and Redisto obtain user data corresponding comparison is performed (each time a user carries this access token, the server to Redisthe user to verify whether there).

    ④, Disadvantages: must be deployed Redis, each must visit Redis, IOcost is particularly great.

2. Final Solution: Use JWT realize Token Authentication

  • JWT principle

    After authentication server generates a JSON object back to the user, after the user and server communication time, we should send back the JSON object. Server completely rely on the object identified user. To prevent users from tampering with data, the server when generating the object, the signature will be added. That server does not save any session data, and that is the server becomes stateless, and thus relatively easy to achieve expansion.

    简单来说,就是通过一定规范来生成 token,然后可以通过解密算法逆向解密 token,这样就可以获取用户信息
  • pros and cons

    Pros: Production token can contain basic information, such as id, user nicknames, avatars and other information, check the library to avoid re-; stored in the client, not the server's memory resources

    Disadvantage: token base64 encoding is the result, it is possible to decode the token before encryption so the object should not contain sensitive information (e.g., user permissions, passwords, etc.)

  • JWT format consists of: head + load + signature (header + payload + signature)

    Head: mainly describe signature algorithm.

    Load: describes the encrypted object information, such as user id, etc., can also add some stuff inside specifications, such as iss issuer, expiration time exp, Sub-oriented user.

    Signature: The main part is the first two encryption, to prevent the others to get the token be decrypted base tampering token.

Figure 3. Case Design

Third, the code demonstrates Case

  • and introducing pom.xml file dependent entity class
    <!-- 依赖可以减少实体类 getter/setter等方法书写 -->
    <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <optional>true</optional>
    </dependency>
    <!-- JWT相关 -->
    <dependency>
       <groupId>io.jsonwebtoken</groupId>
       <artifactId>jjwt</artifactId>
       <version>0.7.0</version>
    </dependency>
    
    ====================================================================================
    
    @Getter
    @Setter
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public class User implements Serializable {
    
        private Integer id;
        private String openid;
        private String name;
        private String headImg;
        private String phone;
        private String sign;
        private Integer sex;
        private String city;
        private Date createTime;
    
    }
  • JWT generation tools
    public class JwtUtil {
    
        // 主题
        public static final String SUBJECT = "RookieLi";
    
        // 秘钥
        public static final String SECRETKEY = "Rookie666";
    
        // 过期时间
        public static final long EXPIRE = 1000 * 60 * 60 * 24 * 7;  //过期时间,毫秒,一周
    
        // 生成 JWT
        public static String geneJsonWebToken(User user) {
    
            if (user == null ||
                    user.getId() == null ||
                    user.getName() == null ||
                    user.getHeadImg() == null) {
    
                return null;
            }
            String token = Jwts.builder()
                    .setSubject(SUBJECT)
                    .claim("id", user.getId())
                    .claim("name", user.getName())
                    .claim("img", user.getHeadImg())
                    .setIssuedAt(new Date())
                    .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                    .signWith(SignatureAlgorithm.HS256, SECRETKEY).compact();
    
            return token;
        }
    
    
        // 校验 JWT
        public static Claims checkJWT(String token) {
    
            try {
                final Claims claims = Jwts.parser().setSigningKey(SECRETKEY).
                        parseClaimsJws(token).getBody();
                return claims;
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
  • JWT test tools
    public class JwtUtilTest {
    
        @Test
        public void testGeneJwt(){
    
            User user = new User();
            user.setId(999);
            user.setHeadImg("I'm busy");
            user.setName("Rookie");
            String token = JwtUtil.geneJsonWebToken(user);
            System.out.println(token);
    
        }
    
    
        @Test
        public void testCheck(){
    
            // 下面此 token 字符串是上面的结果生成的,每次不一样,不是写死的
            String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJSb29raWVMaSIsImlkIjo5OTksIm5hbWUiOiJSb29raWUiLCJpbWciOiJJJ20gYnVzeSIsImlhdCI6MTU2NzMxNjk4NywiZXhwIjoxNTY3OTIxNzg3fQ.FJh41VwVh2gh5-_cOG0SOgoO3dR_ZcK9VWNNskWqKl0";
            Claims claims = JwtUtil.checkJWT(token);
            if(claims != null){
                String name = (String)claims.get("name");
                String img = (String)claims.get("img");
                int id =(Integer) claims.get("id");
                System.out.println(name);
                System.out.println(img);
                System.out.println(id);
            }else{
                System.out.println("非法token");
            }
        }
    }

    Reference blog:

    http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

    https://www.cnblogs.com/jpfss/p/10929458.html

Guess you like

Origin www.cnblogs.com/miantiao312/p/11442187.html