JWT (JSON Web Token) detailed explanation and examples

Table of contents

1. What is JWT?

2. When to use JWT?

3. JWT format

1、Header

2、Payload

3、Signature

4. JWT implementation:


Official website

1. What is JWT?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way to securely transmit information as a JSON object between parties.
JWT can be signed using a password (using the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

The signed token can use the algorithm in JWT to verify the integrity of json.

2. When to use JWT?

  1. Authorize
  2. information exchange
  3. Usage: The server generates a token according to the specification and issues it to the client (save it on the client). At this time, the client can carry the token when requesting the server and use the token to prove its identity information.
  4. The frontend puts the JWT into the Authorization bit in the HTTP Header on every request. (solve XSS and XSRF issues)

JWT Advantages
    Simplicity: It can be sent through URL, POST parameters or HTTP Header, because the data volume is small and the transmission speed is fast
    From Contains: The payload contains all the information required by the user, avoiding multiple queries to the database
    Because the Token is stored on the client in JSON encrypted form, JWT is cross-language, in principle Any web form is supported
    There is no need to save session information on the server side, and it is especially suitable for distributed microservices.
    More suitable for mobile terminals: When the client is a non-browser platform, cookies are not supported. At this time, using the token authentication method will be much simpler
     Single sign-on friendly: Since cookies cannot cross domains, it is difficult to achieve single sign-on. However, if token is used for authentication, the token can be stored in the memory of the client at any location, not necessarily a cookie, so it does not rely on cookies and will not have these problems
 

3. JWT format

Use three parts separated by commas:

  • Header
  • Payload
  • Signature
    token 格式:xxxxx.yyyyy.zzzzz

Header usually consists of two parts: token type and signature algorithm name. It is the first part of the token
For example:

{
"alg": "HS256", // 签名算法
"typ": "JWT" // token类型
}

This JSON is then encoded using Base64Url and placed in the first part of the JWT.

2、Payload

Payload is the second part of the token. It contains some claims. The name of the claim must be unique.
Claims are statements that contain user data and other data.

There are three types of declarations:

  1. Registered Claim Name
    Some predefined claims (use them if necessary, don’t use them if not):
  • "iss"
  • "sub"
  • "aud"
  • "exp"
  • "nbf"
  • "iat"
  • "jti"

See more JSON Web Token (JWT)

  1. Public Claim Names
    Public claims can be pre-defined in IANA JSON Web Token Registry , Or define it in a place that can resolve name conflicts.

  2. Private Claim Names
    Private names used by both parties to share data. Neither Registered Claim Name nor Public Claim Names.

payload example

{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

JSON 

This JSON is then encoded using Base64Url and placed into the second part of the JWT.

3、Signature

Get the encoded header and encoded payload and use the password to sign them.

Example of signing using HMAC SHA256:

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

Signature needs to use the encoded header and payload and a secret key we provide, and then use the signature algorithm specified in the header to sign. The purpose of the signature is to ensure that the JWT has not been tampered with.

HMACSHA256(base64UrlEncode(header)+“.”+base64UrlEncode(payload),secret)

In fact, the header information and payload content are signed to prevent the content from being tampered with. If someone decodes the header and payload content, modifies it, then encodes it, and finally adds the previous signature combination to form a new JWT, then the server The client will determine that the signature formed by the new header and payload is different from the signature attached to the JWT. If you want to sign new headers and payloads, the results will be different because you don’t know the secret key used by the server for encryption.

Note: The secret is stored on the server side, and the jwt issuance is also generated on the server side. The secret is used for jwt issuance and jwt verification, so it is your server's private key and should not be exposed in any scenario.

4. JWT implementation:

  1. Dependency introduction

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jwt-jsonwebtoken.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>RELEASE</version>
        </dependency>

2. Generate Token 

// 签名密钥
 private static final String SECRET = "!Doker$";
public String createToken(Map<String, Object> claims, String subject) {
        final Date createdDate = clock.now();
        final Date expirationDate = calculateExpirationDate(createdDate);
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(createdDate)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, Algorithm.HMAC256(SECRET))
                .compact();
    }

    private Date calculateExpirationDate(Date createdDate) {
        return new Date(createdDate.getTime() + expiration * 1000);
    }

3. Refresh Token 

public String RefreshToken(String token) {
        final Date createdDate = clock.now();
        final Date expirationDate = calculateExpirationDate(createdDate);
        final Claims claims = getAllClaimsFromToken(token);
        claims.setIssuedAt(createdDate);
        claims.setExpiration(expirationDate);
        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, Secret)
                .compact();
    }

4. The token is sent to the front end
Pass in the current user's functions and user information, the login name generates a token, and writes it into the return header of the response. The front end obtains it and saves it in the front end. In the local cache, subsequent front-end requests must put the token in the header.

//登录成功之后
List<Object> functs=(List<Object>) authResult.getAuthorities();
//当前功能列表
String loginName=authResult.getName();//登录名
Users obj=(Users)authResult.getPrincipal();//用户信息
String token=JwtUtil.createToken(loginName,functs,obj);

//生成token  TOKEN_HEADER= Authorization TOKEN_PREFIX=Bearer token值
response.setHeader(JwtUtil.TOKEN_HEADER,JwtUtil.TOKEN_PREFIX+token);
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK); //个人编写的视图对象
DTO dto=new DTO<>();
dto.setCode("000000");
dto.setMessage("认证通过");

PrintWriter pw=response.getWriter();
pw.write(JsonUtil.set(dto));//写入json
pw.flush();//强制刷新
pw.close();//关闭流

5. Verify that the user requests to carry the token

String header = request.getHeader(JwtUtil.TOKEN_HEADER);
 if (null == header || !header.toLowerCase().startsWith(JwtUtil.TOKEN_PREFIX)) { 
  // 如果头部 Authorization 未设置或者不是 basic 认证头部,则当前 
  // 请求不是该过滤器关注的对象,直接放行,继续filter chain 的执行
   chain.doFilter(request, response);
   return;
} 

try {
  String token = header.replace(JwtUtil.TOKEN_PREFIX, ""); 
  // 验证token是否过期
  if (JwtUtil.isExpiration(token)) { 
      throw new javax.security.sasl.AuthenticationException("token 验证不通过");
} 

//檢查token是否能解析
Users user = (Users) JwtUtil.getUser(token); 
if (null == user) { 
    throw new javax.security.sasl.AuthenticationException("token 验证不通过");
} 

//验证成功

Guess you like

Origin blog.csdn.net/leesinbad/article/details/128012582