当前位置:网站首页>JWT certification

JWT certification

2022-07-07 06:32:00 Lingyixuan

JWT

1. JWT What is it? ?

​ JSON Web Token (JWT) is an open standard (RFC 7519 ) that defines a compact and self-contained way for securelytransmitting information between parties as a JSON object. This information can be verified and trusted because it is digitllysigned.JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA orECDSA.

 Official website address : https://jwt.io/introduction/
 translate : jsonwebtoken (JWT) It's an open standard (rfc7519), It defines a compact 、 The self-contained way , Used between parties to JSON Objects transmit information securely . This information can be verified and trusted , Because it's digitally signed .jwt You can use secrets ( Use HNAC Algorithm ) Or use RSA or ECDSA The public key / The private key pair is signed 

 Popular explanation 
JWT abbreviation .JSON Web Token , That is, through .JSON Formal act Web Token in application , Used to securely treat information as between parties JSON Object transfer . Data encryption can also be completed in the process of data transmission 、 Signature and other related processing .

2. JWT What can be done

1. to grant authorization 
	 This is the use of JWT The most common solution . Once the user logs in , Each subsequent request will include JWT, This allows the user to access the route allowed by the token , Services and resources . Single sign on is widely used today JWT A feature of , Because it costs little and can be easily used in different domains .
2. Information switching 
	JSON Web Token It's a good way to safely transfer information between parties . Because you can be right JWT To sign 《 for example , Use public key / Private key pair ), So you can make sure that the sender is the person they are talking about . Besides , Because the signature is computed using headers and payloads , So you can also verify that the content has been tampered with .

3. Why JWT

Traditional based session authentication

  • 1. authentication
	 We know ,http Protocol itself is a stateless protocol , This means that if the user provides a user name and password to our application for user authentication , So the next time you ask , The user has to do user authentication again , Because according to http agreement , We don't know which user made the request , So in order for our application to recognize which user made the request , We can only store one copy of user login information on the server , This login information will be passed to the browser in response , Tell it to save as cookie, So that the next request can be sent to our app , In this way, our application can recognize that the request comes from users , This is the basis of tradition session authentication .
  • 2. The certification process
img
  • 3. Expose the problem

    1.  After each user has passed our application authentication , Our applications all need to record the value at the server once , In order to facilitate the identification of the user's next request , generally  session  It's all stored in memory , And with the increase of authenticated users , The cost of the server will increase obviously 
    
    2.  After user authentication , The server makes authentication records , If the authentication record is stored in memory , This means that the next time a user requests it, he must request it on this server . In this way, we can get the authorized resources , So in distributed applications , Accordingly, the capacity of load balancer is limited . This also means that the expansion ability of the application is limited .
    
    3.  Because it's based on cookie For user identification ,cookie  If intercepted . Users will be vulnerable to cross site request forgery attacks .
    
    4.  It's even more painful in the front and rear separation system :
    	 The front and back end separation increases the complexity of deployment after application decoupling . Usually, users have to forward multiple requests in a single request . If you use session Every time sessionid To the server , The server also needs to query user information . At the same time, if there are many users . This information is stored in the server memory , Add a load to the server . And that is CSRF( Cross site forgery request attack ) attack ,session Is based on cookie For user identification ,cookie If it is hidden , Users will be vulnerable to cross site request forgery attacks . And that is sessionid It's an eigenvalue . The information expressed is not rich enough . It's not easy to expand . And if your application is multi node deployment . Then we need to achieve session Sharing mechanism . It is not convenient for cluster application .
    

JWT The authentication process

4. JWT What's the structure of the system ?

Token composition

token string  ====>  header.payload.signature token
1.  header (Header)
2.  Payload (Payload)
3.  Signature (Signature)
   +  therefore ,JWT Usually as follows :xxxxx.yyyyy.zzzzz   Header.Payload.Signature
2.Header
 The header usually consists of two parts : Type of token ( namely JWT) And the signature algorithm used , for example HINAC SHA256 or RSA. It will use Base64 Code composition JWT The first part of the structure .
-  Be careful :Base64 It's a kind of coding , in other words , It can be translated back to the original . It's not an encryption process .
{
    
    "alg" : "HS256",
    "typ" : "JWT"
}
3.Payload
 The second part of the token is the payload , It contains a statement . The declaration is about the entity ( Usually the user ) Claims and other data . alike , It will use Base64 Code composition JWT The second part of the structure 
{
    
    "sub" : "1234567890",
    "name" : "John Doe",
    "admin" : true
}
4.Signature
-  The first two parts use Base64 Coded , That is, the front end can unlock the information inside .Signature You need to use the encoded  header  and  payload  And a key we provided , And then use  header  The signature algorithm specified in (HS256) To sign . The purpose of signature is to guarantee JWT It has not been tampered with 
    
-  Such as :
	HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload) ,secret);
# Signature purpose 
-  The last step in the process of signing , It's actually signing the header and payload content . Prevent content from being tampered with . If someone decodes the header and the content of the load and then modifies it before encoding , Finally, add the previous signature combination to form a new JWT Words , Then the server side will determine the signature and JWT The signature attached is different . If you want to sign the new header and payload , If you don't know the key used by the server for encryption , The signature is also different .

# Information security issues 
-  Here we will ask a question :Base64 It's a kind of coding , It's reversible , Then my information was exposed ?
-  Yes . therefore , stay JWT in , No sensitive data should be added to the load . In the example above , We transmit the user's User ID. This value is actually not sensitive , It's generally known to be safe . But content like passwords can't be placed in JWT It's in . If you put the user's password in JWT in , Then a malicious third party passes through Base64 Decode it and you'll soon know your password . therefore JWT Suitable for applying to Web Applications deliver some non sensitive information .JWT It is also often used to design user authentication and authorization systems , Even realize Web Single sign on for applications .
#5. Put together 
-  The output is three dots separated Base64-URL character string , Can be in HTML and HTTP These strings are easily passed in the environment , And based on XMNL Standards for ( for example SAML) comparison , It's more compact .
-  concise (Compact)  Can pass URL,POST Parameters may be in  HTTP header send out , Because of the small amount of data , Fast transmission speed 
-  Self contained (Self-contained)
 The load contains all the information the user needs , Avoid multiple queries to the database 
eyJhbGci0iJIUzI1NiIsInR5cCI6IkpXVc.xp.
eyJzdWI:OiIxMjMGNTY30DkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaXNTb2NpYWwiOnRydwv9.
4pcPyMD09olPSyxnrXCjTwXyr4BsezdI1AVTmud2fU4

5. Use JWT

#  First step : Introduce dependencies 
<dependency>
	<groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.1</version>
</dependency>
<!-- introduce  jar-->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.1</version>
</dependency>

<!-- introduce  Mybatis-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

<!-- introduce  lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

<!-- introduce  druid-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
</dependency>

<!-- introduce  mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

Simple test cases :

@SpringBootTest
class SpringBootJWtApplicationTests {
    

    public static final String SIGNATURE = "tiofjdifjaihu899#(*U(*#@";
    private String token;

    @Test
    public void contextLoads() {
    
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND, 90);
		
        #  The second step :  Generate  token
        String token = JWT.create()
                .withClaim("username", "Zhang San")
                .withClaim("password", "Java")
                .withExpiresAt(instance.getTime())  //  Expiration time 
                .sign(Algorithm.HMAC256(SIGNATURE));

        this.token = token;
        System.out.println(" token  = " + token);
		
        #  Parse data based on token and signature 
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SIGNATURE)).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        System.out.println(" user name  : " + decodedJWT.getClaim("username").asString());
        System.out.println(" The secret   code  : " + decodedJWT.getClaim("password").asString());
        System.out.println(" Expiration time  : " + decodedJWT.getExpiresAt());
    }
}
#4. Common exception information 
- SignatureVerificationException:   Signature inconsistency exception 
- TokenExpiredException:  Token expiration exception 
- AlgorithmMismatchException:  Algorithm mismatch exception 
- InvalidClaimException:  Invalid payload abnormal 

6. The actual case

database

CREATE DATABASE jwt;
USE jwt;
CREATE TABLE `user` (
	`id` INT ( 11 ) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ',
	`name` VARCHAR ( 40 ) DEFAULT NULL COMMENT ' user name ',
	`password` VARCHAR ( 40 ) DEFAULT NULL COMMENT ' The secret   code ',
PRIMARY KEY ( `id` ) 
) ENGINE = INNODB AUTO_INCREMENT = 2 CHARSET = utf8;

Add a piece of data to the database

INSERT INTO user(name, password) VALUE('zhangsan', '123');

Project structure chart

applicatoin.yaml Profile contents

server:
  port: 8081

spring:
  application:
    name: SpringBootJWt
  datasource:
    username:  Database user name 
    password:  Database password 
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:// The server IP Address : port /jwt?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true

mybatis:
  type-aliases-package: com.jwt.entity
  mapper-locations: mapper/UserMapper.xml
logging:
  level:
    com.jwt.dao: debug

User Entity class

@Data
public class User {
    
    private String id;
    private String name;
    private String password;
}

UserDao

@Mapper
public interface UserDao {
    
    User login(@Param("user") User user);
}

Project structure chart

 Insert picture description here

UserMapper

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jwt.dao.UserDao">
    <select id="login" resultType="com.jwt.entity.User">
        select * from user where name=#{
    user.name} and password=#{
    user.password}
    </select>
</mapper>

UserService

public interface UserService {
    
    User login(User user);
}

UserServiceImpl

@Service
@Transactional
public class UserServiceImpl implements UserService {
    

    @Autowired
    private UserDao userDao;

    @Override
    public User login(User user) {
    
        User login = userDao.login(user);
        if(login != null)
            return login;
        throw new RuntimeException(" Login failed ");
    }
}

JWTUtils

public class JWTUtils {
    

    public static final String SIGNATURE = "fudsifu98ewqurw90ur&^*()#(JI()WEPJBVDS";

    //  Generate  token
    public static String getToken(Map<String, String> map){
    
        JWTCreator.Builder builder = JWT.create();
        map.forEach((key, value)->{
    
            builder.withClaim(key, value);
        });

        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.MINUTE, 7);
        builder.withExpiresAt(instance.getTime());
        return builder.sign(Algorithm.HMAC256(SIGNATURE));
    }


    /** *  verification  token  Legitimacy  * @param token */
    public static void verify(String token){
    
        JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
    }

    /** *  obtain  token  Information methods  * @param token * @return */
    public static DecodedJWT getToken(String token){
    
        return JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
    }
}

JWTInterceptor

public class JWTInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
        String token = request.getHeader("token");

        Map<String, Object> map = new HashMap<>();
        try {
    
            JWTUtils.verify(token);
            return true;
        }catch (SignatureVerificationException e) {
    
            map.put("msg", " Inconsistent signature ");
            e.printStackTrace();
        }catch (TokenExpiredException e){
    
            map.put("msg", " The token expired ");
            e.printStackTrace();
        } catch (AlgorithmMismatchException e){
    
            map.put("msg", " Algorithm mismatch ");
            e.printStackTrace();
        }catch (InvalidClaimException e){
    
            map.put("msg", " Abnormal load ");
            e.printStackTrace();
        }

        map.put("state", false);
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=utf8");
        response.getWriter().println(json);
        return false;
    }
}

InterceptorConfig

@Component
public class InterceptorConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/user/test")
                .excludePathPatterns("/user/login");  //  For login, all directions , Other  token  verification 
    }
}

UserController

@RestController
@Slf4j
public class UserController {
    

    @Autowired
    private UserService userService;

    @GetMapping("/user/login")
    public Map<String, Object> login(User user) {
    

        log.info(" User name  : [{}]", user.getName());
        log.info(" User password  : [{}]", user.getPassword());
        HashMap<String, Object> hashMap = new HashMap<>();
        try {
    
            User login = userService.login(user);

            HashMap<String, String> payload = new HashMap<>();
            payload.put("id", login.getId());
            payload.put("name", login.getName());
            payload.put("password", login.getPassword());
            String token = JWTUtils.getToken(payload);
            hashMap.put("state", true);
            hashMap.put("msg", " Authentication success ");
            hashMap.put("token", token);
        } catch (Exception e) {
    
            hashMap.put("state", false);
            hashMap.put("msg", e.getMessage());
        }
        return hashMap;
    }

    //  The first edition , Directly verify when logging in 
    //@PostMapping("/user/test")
    //public Map<String, Object> test(String token) {
    
    // Map<String, Object> map = new HashMap<>();
    // log.info(" At present  token  by  {}", token);
    //
    // try {
    
    // DecodedJWT verify = JWTUtils.getToken(token);
    // map.put("state", true);
    // map.put("msg", " The request is successful !");
    // return map;
    // } catch (SignatureVerificationException e) {
    
    // map.put("msg", " Inconsistent signature ");
    // e.printStackTrace();
    // }catch (TokenExpiredException e){
    
    // map.put("msg", " The token expired ");
    // e.printStackTrace();
    // } catch (AlgorithmMismatchException e){
    
    // map.put("msg", " Algorithm mismatch ");
    // e.printStackTrace();
    // }catch (InvalidClaimException e){
    
    // map.put("msg", " Abnormal load ");
    // e.printStackTrace();
    // }
    //
    // map.put("state", false);
    // return map;
    //}


    //  The second edition , After logging in , No need to verify , But every time I ask, I will bring  token, token  Process in the interceptor 
    //  After registration , Front end carrying token  Put it on the  token  in , Back end from  request  Get from the request header in 
    @PostMapping("/user/test")
    public Map<String, Object> test(HttpServletRequest request) {
    
        Map<String, Object> map = new HashMap<>();
        String token = request.getHeader("token");
        DecodedJWT verify = JWTUtils.getToken(token);

        log.info(" user  id : " + verify.getClaim("id").asString());
        log.info(" user  name : " + verify.getClaim("name").asString());
        log.info(" user  password : " + verify.getClaim("password").asString());

        log.info(" Expiration time  : " + verify.getExpiresAt());

        map.put("msg", " Authentication success ");
        map.put("state", true);
        return map;
    }
}
原网站

版权声明
本文为[Lingyixuan]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207070154333523.html