Simple user login verification based on JWT (super detailed)

1. What is JWT

JSON Web Token (JWT) is currently the most popular cross-domain authentication solution .

2. What JWT is generally used for

  • authorized 

That is, after the user logs in successfully, a token (token) is issued to the user, and the user can use this token to access the background interface

  • encryption

JWT can be used to encrypt the parameters of the interface, and it can only be processed after the background verification is successful.

3. Why use JWT for authentication instead of session and cookie?

Cookie-based authentication has the following problems:

  • CSRF : session is based on cookie, if the cookie is intercepted, users are vulnerable to cross-site request forgery attacks.

Session-based authentication has the following problems:

  • High overhead : After each user is authenticated, a record must be made on the server side to facilitate the identification of the user's next request. Usually the session is stored in the memory. With the increase of authenticated users, the overhead of storing the session on the server increases significantly.
  • Low scalability : User authentication records are stored in the memory of the authentication server, which means that the user still needs to access this server to obtain authorization for the next request. In distributed applications, this limits the ability of load balancing, which in turn limits the scalability of the entire application.

JWT is a token-based authentication mechanism, which is stateless like the HTTP protocol, and does not need to retain user authentication information or session information on the server side. In addition, the token-based authentication mechanism does not need to consider which server the user logs in, which provides convenience for application expansion.

       Having said so much, let's use a small case to practice~

Environment preparation:

      A simple springboot project:

      Basic user entity class:

package com.example.mybatixtest.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;

import com.sun.xml.internal.ws.developer.Serialization;
import lombok.Data;

/**
 * 
 * @TableName user
 */
@TableName(value ="user")
@Data
@Serialization
public class User implements Serializable {
    /**
     * 
     */
    private String userId;

    /**
     * 
     */
    private String username;

    /**
     * 
     */
    private String password;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

 1. We first import the jwt dependency in the pom.xml file

        <!--引入jwt-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.9.0</version>
        </dependency>

2. Create a JWT tool class to encapsulate JWT related operations (encryption, verification, decryption)

package com.canrio.onlinemusic.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class TokenUtil {

    private static final long EXPIRE_TIME= 15*60*1000;
    private static final String TOKEN_SECRET="token123";  //密钥盐

    /**
     * 签名生成
     * @return
     */
    public static String sign(String name,String userId){

        String token = null;
        try {
            Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            token = JWT.create()
                    .withIssuer("auth0").withClaim("id","id")
                    .withClaim("username", name)
                    .withClaim("userId",userId)
                    .withExpiresAt(expiresAt)
                    // 使用了HMAC256加密算法。
                    .sign(Algorithm.HMAC256(TOKEN_SECRET));
        } catch (Exception e){
            e.printStackTrace();
        }
        return token;

    }
    /**
     * 签名验证
     * @param token
     * @return
     */
    public static boolean verify(String token){

        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
            DecodedJWT jwt = verifier.verify(token);
            System.out.println("认证通过:");
            System.out.println("issuer: " + jwt.getIssuer());
            System.out.println("username: " + jwt.getClaim("username").asString());
            System.out.println("userId: " + jwt.getClaim("userId").asString());
            System.out.println("id"+jwt.getClaim("id").asString());
            System.out.println("过期时间:      " + jwt.getExpiresAt());
            return true;
        } catch (Exception e){
            return false;
        }
    }

    public static String getId(String token){


            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
            DecodedJWT jwt = verifier.verify(token);
            String id = jwt.getClaim("userId").asString();
            return id;

        }
}

3. Create a login interceptor LoginInterceptor to obtain the requested Token and verify it

package com.example.mybatixtest.interceptor;

import com.example.mybatixtest.utils.TokenUtil;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component   //在容器中进行注册
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            System.out.println("OPTIONS请求,放行");
            return true;
        }
        String token = request.getHeader("token");
        if(TokenUtil.verify(token)){
            return true;
        }
        // 失败我们跳转回登录页面
        request.setAttribute("msg","登录出错");
        request.getRemoteHost();
        request.getRequestDispatcher("/login").forward(request,response);
        return false;
    }

}

4. Modify the web configuration, add a configuration class WebConfig to register LoginInterceptor and formulate interception rules

package com.example.mybatixtest.config;

import com.example.mybatixtest.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//@Configuration 告诉springboot这是一个配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(loginInterceptor)
                        .addPathPatterns("/**")   //默认对所有请求进行拦截
                        .excludePathPatterns("/userLogin","/static/**");     //对login页面和静态资源不拦截
    }
}

 5. We write simple requests for verification

 @GetMapping(value = "/userLogin")
    public String userLogin(@RequestParam("username") String username, @RequestParam("password") String password) {
        //创建一个条件构造器
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>();
        //传入查询条件

        userQueryWrapper.eq("username", username).eq("password", password);
        User user = userService.getOne(userQueryWrapper);
        if (user != null) {
            String res = TokenUtil.sign(username, user.getUserid());
            System.out.println(res);
            return res;
        }

        return "失败";

    }

6. Using postman to verify, we can find that the client has obtained a string of token strings

 7. Here I use the small project I did before to verify the token

/**
     * 根据返回的token解析用户id并返回该用户的歌单列表
     *
     * @return
     */
    @GetMapping("/getUserFolderByUserId")
    public List<UserFolder> getUserFolderByUserID() {
        String token = request.getHeader("token");
        System.out.println(token);
        String id = TokenUtil.getId(token);
        QueryWrapper<UserFolder> userFolderQueryWrapper = new QueryWrapper<>();
        userFolderQueryWrapper.eq("user_userid", id);
        List<UserFolder> list = userFolderService.list(userFolderQueryWrapper);
        System.out.println(list);
        return list;
    }

When our request header does not carry token:

When we carry: 

 

So far, our simple user login verification tutorial based on JWT is over~

Thank you for reading, I hope my article can bring you help! ! !

Guess you like

Origin blog.csdn.net/weixin_47025166/article/details/125373122