3,CSRF
Because user identification is based on cookies, if cookies are intercepted, users will be vulnerable to cross site request forgery attacks.
5, Authentication mechanism based on token
The token based authentication mechanism is similar to http protocol and is stateless. It does not need to retain the user's authentication information or session information at the server. This means that applications based on token authentication mechanism do not need to consider which server users log in, which provides convenience for application expansion.
The process is as follows:
-
The user uses the user name and password to request the server
-
The server authenticates the user's information
-
The server sends a token to the user through authentication
-
The client stores the token and attaches the token value to each request
-
The server verifies the token value and returns data
This token must be passed to the server at each request. It should be saved in the request header. In addition, the server should support CORS (cross source resource sharing) policy. Generally, we can do this at the server. Access control allow origin: *.
So let's return to the topic of JWT.
6, What does JWT look like?
JWT is composed of three pieces of information, which are used as text The links together form a JWT string. Like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
7, Composition of JWT
The first part is called the head, the second part is called the payload, and the third part is the signature.
1,header
The header of jwt carries two parts of information:
-
Declaration type, here is jwt
-
The algorithm for declaring encryption usually uses HMAC SHA256 directly
The complete header is like the following JSON:
{ 'typ': 'JWT', 'alg': 'HS256' }
Then the header is encrypted with base64 (the encryption can be decrypted symmetrically), forming the first part.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2,playload
Payload is the place where valid information is stored. The name seems to refer specifically to the goods carried on the aircraft. These valid information contains three parts
-
Declaration registered in the standard
-
Public statement
-
Private declaration
Declaration registered in the standard (recommended but not mandatory):
-
iss: jwt issuer
-
Sub: the user JWT is targeting
-
aud: party receiving jwt
-
Exp: the expiration time of JWT, which must be greater than the issuing time
-
nbf: define the time before which the jwt is unavailable
-
IAT: issuing time of JWT
-
JTI: the unique identity of JWT, which is mainly used as a one-time token to avoid replay attacks.
Public statement:
Any information can be added to the public statement. Generally, the user's relevant information or other necessary information required by the business can be added However, it is not recommended to add sensitive information because this part can be decrypted on the client
Private declaration:
Private declaration is a declaration jointly defined by providers and consumers. It is generally not recommended to store sensitive information, because base64 is symmetrically decrypted, which means that this part of information can be classified as plaintext information.
Define a payload:
{ "sub": "1234567890", "name": "John Doe", "admin": true }
Then it is encrypted with base64 to get the second part of Jwt.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
3,signature
The third part of jwt is a visa information, which consists of three parts:
-
Header (after Base64)```
fetch('api/user/1', {
headers: {
'Authorization': 'Bearer ' + token
}
})
-
Payload (after Base64)
-
secret
This part requires base64 encrypted header and base64 encrypted payload The third part of jwt is formed by connecting the strings, and then performing salt secret combination encryption through the encryption method declared in the header.
// javascript var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
Use these three parts Connected into a complete string to form the final jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
Note: secret is saved on the server side, and jwt issuance is also generated on the server side. Secret is used for jwt issuance and jwt verification. Therefore, it is the private key of your server side and should not be revealed in any scenario. Once the client knows the secret, it means that the client can sign jwt it.
8, How to apply
Authorization is usually added to the request header and marked with Bearer:
The server will verify the token, and if it passes the verification, it will return the corresponding resources. The whole process is like this:
9, JWT tool class
@Configuration @ConfigurationProperties(prefix = "jwt.token") public class JwtTokenUtil { public static void setSecret(String secret) { JwtTokenUtil.secret = secret; } public static void setExpiration(int expiration) { JwtTokenUtil.expiration = expiration; } private static String secret="winner"; private static int expiration=7200; private static final String CLAIM_KEY_USERNAME="sub"; private static final String CLAIM_KEY_ID="id"; private static final String CLAIM_KEY_CREATED="created"; private static final String CLAIM_KEY_ROLES="roles"; //Get the user from the obtained token public static String getUsernameFromToken(String token){ String username; try { username=getClaimsFromToken(token).getSubject(); }catch (Exception e){ username=null; } return username; } //Get the time in the token public static Date getCreatedDateFromToken(String token){ Date date; try { final Claims claims=getClaimsFromToken(token); date=new Date((Long)claims.get(CLAIM_KEY_CREATED)); }catch (Exception e) { date=null; } return date; } //Get expiration time from token public static Date getExpirationDateFromToken(String token) { Date expiration; try { final Claims claims = getClaimsFromToken(token); expiration = claims.getExpiration(); } catch (Exception e) { expiration = null; } return expiration; } //Parse token private static Claims getClaimsFromToken(String token){ Claims claims; try { claims = Jwts.parser().setSigningKey(secret).parseClaimsJwt(token).getBody(); }catch(ExpiredJwtException e){ claims=e.getClaims(); } return claims; } //Build expiration time private static Date generateExpirationDate(){ //Expiration event return new Date(System.currentTimeMillis()+ expiration); } //The information in userDetails is added to the token and generateToken is called to produce the token public static String generateToken(Employee userDetails){ Map<String,Object> claims=new HashMap<>(); claims.put(CLAIM_KEY_USERNAME,userDetails.getUsername()); claims.put(CLAIM_KEY_CREATED,new Date()); claims.put(CLAIM_KEY_ID,userDetails.getENo()); claims.put(CLAIM_KEY_ROLES,userDetails.getRoles());