SpringBoot (9) jwt + interceptor implementa verificación de token

    En los filtros e interceptores de los dos artículos anteriores, hemos mencionado que podemos hacer cosas como la verificación de permisos. http/https es un protocolo sin estado. Cuando un usuario accede a una interfaz de back-end, ¿cómo juzgar si el usuario tiene permiso? Por supuesto, puede usar cuenta + contraseña para verificar. Sin embargo, si usa un número de cuenta y una contraseña, necesita acceder a la base de datos con frecuencia, obviamente, traerá algunos gastos generales adicionales. Este artículo presenta el uso de jwt e interceptores para implementar la verificación de permisos de token.     

    Si es un novato y no ha leído mi serie anterior de artículos de SpringBoot, se recomienda al menos leer este:

SpringBoot (4) SpringBoot construye un server_springboot simple hace un blog envenenado service_heart-CSDN blog

    Si desea estudiar sistemáticamente de principio a fin, preste atención a mi columna y siga actualizando:

https://blog.csdn.net/qq_21154101/category_12359403.html

Tabla de contenido

​​​​​​​1. El servidor genera un token

1. Agregar dependencia de token

2. Herramientas simbólicas

2. El cliente lleva el token

1. Obtener token al registrarse

2. Llevar el token al solicitar

3. Verificar token después de la solicitud

1. Interceptor de fichas

2. Interceptor de fichas de registro

3. Solicitud y verificación del cliente


 

​​​​​​​1. El servidor genera un token

1. Agregar dependencia de token

		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.4.1</version>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.9.1</version>
		</dependency>

2. Herramientas simbólicas

    Escriba una clase de herramienta para generar y verificar el token

package com.zhaojun.server.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
    private static final String secret = "hand2020";
    private static final Long expiration = 1209600L;

    /**
     * 生成用户token,设置token超时时间
     */
    public static String createToken(String name) {
        //过期时间
        Date expireDate = new Date(System.currentTimeMillis() + expiration * 1000);
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        String token = JWT.create()
                // 添加头部
                .withHeader(map)
                //可以将基本信息放到claims中
                //userName
                .withClaim("userName", name)
                //超时设置,设置过期的日期
                .withExpiresAt(expireDate)
                //签发时间
                .withIssuedAt(new Date())
                //SECRET加密
                .sign(Algorithm.HMAC256(secret));
        System.out.println(token);
        return token;
    }

    /**
     * 校验token并解析token
     */
    public static boolean verifyToken(String token) {
        DecodedJWT jwt;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
            jwt = verifier.verify(token);
            if (jwt.getExpiresAt().before(new Date())) {
                System.out.println("token过期");
                return false;
            }
        } catch (Exception e) {
            //解码异常则抛出异常
            System.out.println("token解析异常:" + e.getMessage());
            return false;
        }
        return true;
    }

}

2. El cliente lleva el token

    Debido a que el token general se coloca en el encabezado, no es posible agregar el encabezado cuando se accede directamente en el navegador.Por supuesto, se pueden usar herramientas como cartero. Yo mismo trabajo en Android y rápidamente escribo varias solicitudes y páginas simples basadas directamente en okhttp, incluido el registro y el inicio de sesión previos. La lógica a implementar es la siguiente:

  • Al registrar un nuevo usuario, se genera un token para informar al cliente, y el cliente guarda el token localmente después de recibir el token.
  • Todas las solicitudes posteriores del cliente llevan el token en el encabezado.
  • Después de que el servidor recibe la solicitud, primero verifica el token y, si el token es legal, se libera.

1. Obtener token al registrarse

    En primer lugar, primero registro una cuenta, la cuenta es de prueba, la contraseña es 123456 y el número de teléfono móvil es 123456. En el código de muestra a continuación, escribí una solicitud de registro usando okhttp.

    private void doRegister() {
        String name = mNameEditText.getText().toString();
        String password = mPasswordEditText.getText().toString();
        String phone = mPhoneEditText.getText().toString();
        if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password) || TextUtils.isEmpty(phone)) {
            Toast.makeText(this, "用户名、手机号或密码为空", Toast.LENGTH_SHORT).show();
        }
        String url = URL + "name=" + name + "&password=" + password + "&phone=" + phone;
        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder()
                        .url(url)
                        .build();
                try {
                    Response response = client.newCall(request).execute();
                    ResponseBody body = response.body();
                    if (body != null) {
                        String result = body.string();
                        Log.d("TTTT",result);
                        Gson gson = new Gson();
                        TypeToken<RegisterResult> typeToken = new TypeToken<RegisterResult>() {
                        };
                        RegisterResult registerResult = gson.fromJson(result, typeToken);
                        if (registerResult != null) {
                            String token = registerResult.getToken();
                            SPUtils.getInstance().put("token", token);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    Después de que el registro sea exitoso, puede ver que el backend devuelve el siguiente json:

2. Llevar el token al solicitar

    El siguiente código de muestra, uso okhttp para escribir un encabezado con una solicitud de token, este token se devolvió y se guardó localmente durante el registro anterior.

    private void tokenLogin() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder()
                        .url(url)
                        .addHeader("token", SPUtils.getInstance().getString("token"))
                        .build();
                try {
                    Response response = client.newCall(request).execute();
                    ResponseBody body = response.body();
                    if (body != null) {
                        String result = body.string();
                        Log.d("TTTT", result);
                        Gson gson = new Gson();
                        TypeToken<LoginResult> typeToken = new TypeToken<LoginResult>() {
                        };
                        LoginResult loginResult = gson.fromJson(result, typeToken);
                        if (loginResult != null) {
                            int code = loginResult.getCode();
                            if (code != 0) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        startLoginActivity();
                                    }
                                });
                            }
                        }
                    }
                } catch (Exception e) {
                    Log.d("TTTT",e.getMessage());
                }
            }
        }).start();
    }

3. Verificar token después de la solicitud

    Todo está listo, la generación y la solicitud de tokens de transporte están listas. A continuación, debe implementar un interceptor de tokens en el backend para interceptar cualquier solicitud que no sea la interfaz de registro. Si pasa la verificación del token, se liberará directamente; de ​​lo contrario, se interceptará y se devolverá un mensaje de error. Aquí se definen dos tipos: el token está vacío y el token no es válido.

1. Interceptor de fichas

package com.zhaojun.server.interceptor;

import com.zhaojun.server.util.JwtUtil;
import com.zhaojun.server.util.TextUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class TokenInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(response);
        String token = request.getHeader("token");
        if (TextUtils.isEmpty(token)) {
            wrapper.sendRedirect("fail/token/null");
            System.out.println("null token");
            return false;
        }
        if (!JwtUtil.verifyToken(token)) {
            wrapper.sendRedirect("fail/token/invalid");
            System.out.println("invalid token");
            return false;
        }
        System.out.println("valid token");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器处理结束...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("请求结束...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

2. Interceptor de fichas de registro

    No se recomienda interceptar directamente todas las URL, solo interceptar las solicitudes requeridas.

package com.zhaojun.server.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TokenInterceptor())
                .addPathPatterns("/login")
                .excludePathPatterns("/register");
    }
}

3. Solicitud y verificación del cliente

Después de que el cliente inicia una solicitud con el token en el encabezado, puede ver que la verificación es exitosa:

Después de usar el navegador para realizar una solicitud sin token, redirija:

Acho que você gosta

Origin blog.csdn.net/qq_21154101/article/details/131820238
Recomendado
Clasificación