One of the problems encountered by cross-domain authentication
Due to the emergence of multiple terminals, through many sites web api restful
in 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 cookie
the Session Id
different approaches, in addition to facing the cross-domain submit cookie
a 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 api
when on comes a by the api
issuing 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
tomcat
application logon test①, stand-alone
tomcat
application login,sesssion
saving between the browser and the application server session, after the user logs in successfully, the server will ensure that asession
will for a clientsessionId
, the client willsessionId
savecookie
each time the user requests will carry thissessionId
.②, multi-node
tomcat
application login, opensession
after data sharing, each server can readsession
. The disadvantage is that eachsession
is 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
session
share①, a real application can not single-node deployment, so there is more than one node login
session
problems to be solved shared.tomcat
Support forsession
sharing, but there are broadcast storm; the user a large amount of time, resource-intensive to severe, is not recommended②,
Reids
clusters, storage landingtoken
outwardly service interfaceRedis
can set the expiration time (using the serverUUID
generates a random64
bit or128
bitstoken
, intoRedis
, and then returned to the client and stored).③, the first time a user logs on successfully, you need to self-generate
token
, and thentoken
returned to the browser and storedcookie
in,
andRedis
on the servertoken
as thekey
user information as thevalue
save. Then subsequent user operation, canHttpServletRequest
directly read the objectcookie
istoken
, andRedis
to obtain user data corresponding comparison is performed (each time a user carries this accesstoken
, the server toRedis
the user to verify whether there).④, Disadvantages: must be deployed
Redis
, each must visitRedis
,IO
cost 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