SpringBoot:JWT+Interceptor 实现基本的登录验证

前置背景

Result类

package com.example.day724test.Dao;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

//统一响应结果
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {
    private Integer code;//业务状态码  0-成功  1-失败
    private String message;//提示信息
    private T data;//响应数据

    //快速返回操作成功响应结果(带响应数据)
    public static <E> Result<E> success(E data) {
        return new Result<>(0, "操作成功", data);
    }

    //快速返回操作成功响应结果
    public static Result success() {
        return new Result(0, "操作成功", null);
    }

    public static Result error(String message) {
        return new Result(1, message, null);
    }
}

Mapper:

Service:

Controler:

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestParam("username") String username, @RequestParam("password") String password) {
        try {
            SysUser user = userService.get_by_name(username);
            if (user == null || !user.getPassword().equals(password)) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
            }
          return ResponseEntity.ok().body(user);

        } catch (Exception e) {
            log.error("登录异常", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");
        }
    }

    /*
    添加一个查看所有的用户的信息方法去验证token相关
     */

    @GetMapping("/all")
    public ResponseEntity<?> getAllUser() {
        try {
            List<SysUser> users = userService.get_all();
            return ResponseEntity.ok().body(users);
        } catch (Exception e) {
            log.error("获取用户列表异常", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");
        }
    }

测试一下是否成功:

login接口:

all接口:

测试成功:步入正题

JSON Web Tokens (JWT) 和拦截器实现登录验证的详细步骤:

. 用户登录
- 用户提交用户名和密码到服务器。
- 服务器验证用户凭证。
- 如果验证成功,服务器生成一个 JWT 并将其返回给客户端。

引入jwt依赖项:这里使用的是版本低一些的

创建JwtUtil类:


    //接收业务数据,生成token并返回
    public static String genToken(Map<String, Object> claims) {
        return JWT.create()
                .withClaim("claims", claims)
                //.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 ))
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7))
                .sign(Algorithm.HMAC256(KEY));
    }




    //接收token,验证token,并返回业务数据
    public static Map<String, Object> parseToken(String token) {
        return JWT.require(Algorithm.HMAC256(KEY))
                .build()
                .verify(token)
                .getClaim("claims")
                .asMap();
    }

测试一波:

生成token:

将生成的token复制准备验证:

 经过验证可以使用去usercontroller实现登录验证:

原来的登录代码:


    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestParam("username") String username, @RequestParam("password") String password) {
        try {
            SysUser user = userService.get_by_name(username);
            if (user == null || !user.getPassword().equals(password)) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
            }
          return ResponseEntity.ok().body(user);

        } catch (Exception e) {
            log.error("登录异常", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");
        }
    }

导入JwtUtil包的token验证代码:

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestParam("username") String username, @RequestParam("password") String password) {
        try {
            SysUser user = userService.get_by_name(username);
            if (user == null || !user.getPassword().equals(password)) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
            }
                /*
                登录成功之后的方法内容
                 */
                Map<String,Object> claims=new HashMap<>();
                claims.put("username",user.getUsername());
                claims.put("password",user.getPassword());
                String token= JwtUtil.genToken(claims);
                log.info("登录成功, 用户名: {}", user.getUsername());
                return ResponseEntity.ok().body(token);
                /*
                在登录接口生成了token
                 */

            /*
            其他的接口需要验证token
             */

        } catch (Exception e) {
            log.error("登录异常", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");
        }
    }

查看是否返回了我们所需要的token信息:

接下来使得其它的接口验证token:验证成功返回数据 否则错误

原来的/user/all:

    @GetMapping("/all")
    public ResponseEntity<?> getAllUser() {
        try {
            List<SysUser> users = userService.get_all();
            return ResponseEntity.ok().body(users);
        } catch (Exception e) {
            log.error("获取用户列表异常", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");
        }
    }

现在的接受token验证登录信息:

   @GetMapping("/all")
   public Result<String> getAllUser(@RequestHeader("Authorization") String token, HttpServletRequest response){ //请求头中获取token
       try {
           Map<String, Object> claims = JwtUtil.parseToken(token);
           return Result.success("所有的文章数据");
       }catch (Exception e){
           return Result.error("未登录");
       }
   }
/*
    在请求头信息中获取token
*/

测试:没有加token的时候

显然在postman测试请求头里面没有携带token所以提示未登录

携带token之后:

请求成功:这便完成了基本的登录检验

但是如果有多个接口 开发大工程项目势必过于繁琐 ,那么我们就使用更加抽象性的方法:使用拦截器

拦截器原理:

拦截器(Interceptors)是一种设计模式,用于在请求到达目标之前或响应离开之后执行某些操作。这种模式在多种编程环境和技术栈中都有应用,包括但不限于HTTP客户端和服务端、数据库访问层、消息队列等。

### 拦截器的基本原理

1. **注册拦截器**:
   - 在应用程序启动时或者某个配置阶段,你需要注册一个或多个拦截器。
   - 每个拦截器通常定义了两个方法:一个用于处理请求前的操作,另一个用于处理响应后的操作。

2. **请求处理**:
   - 当一个请求被发送时,它会先经过一系列预先注册的拦截器。
   - 每个拦截器可以对请求进行一些预处理,比如修改请求头、添加日志记录、验证认证信息等。
   - 如果某个拦截器决定阻止请求继续前进,它可以终止请求流程。
   - 如果请求通过了所有的拦截器,则会被发送到最终的目标。

3. **响应处理**:
   - 当响应从目标返回时,它也会经过相同的拦截器链。
   - 每个拦截器可以对响应进行一些后处理,例如修改响应体、添加额外的响应头等。
   - 响应最终被传递给最初发起请求的代码。

### 应用场景示例

#### AngularJS / Angular

1. **注册拦截器**:
   - 在AngularJS中,你可以通过 `$httpProvider.interceptors` 注册HTTP拦截器。
   - 在Angular中,你可以使用 `HttpClientInterceptor` 类型来创建自定义拦截器。

2. **请求与响应处理**:
   - 当发出一个HTTP请求时,请求会经过所有的请求拦截器。
   - 当收到响应时,响应会经过所有的响应拦截器。

#### Axios

1. **注册拦截器**:
   - Axios 提供了一个简单的API来注册请求和响应拦截器。
   - 可以通过 `axios.interceptors.request.use` 和 `axios.interceptors.response.use` 来注册拦截器函数。

2. **请求与响应处理**:
   - 当请求被发送之前,会依次调用请求拦截器。
   - 当响应被接收到之后,会依次调用响应拦截器。

#### Spring Framework

1. **注册拦截器**:
   - 在Spring MVC中,你可以创建实现了 `HandlerInterceptor` 接口的类,并在配置文件中注册它们。
   - 这些拦截器可以用来处理请求前后的操作。

2. **请求与响应处理**:
   - 当一个请求到达控制器之前,会调用拦截器的 `preHandle` 方法。
   - 如果请求被允许继续,那么在控制器处理完请求后,会调用拦截器的 `postHandle` 方法。
   - 最后,在视图渲染完成后,会调用拦截器的 `afterCompletion` 方法。

### 总结

拦截器提供了一种灵活的方式来扩展应用程序的功能,而不需要直接修改核心逻辑。它们可以在不改变现有代码结构的情况下增加新的功能,例如日志记录、性能监控、认证和授权、错误处理等。拦截器的设计使得系统的模块化程度更高,更易于维护和扩展。

源自黑马程序员springboot讲解 讲的很清楚

具体实现:

  • 继承Interceptor接口,
  • 获取到请求头中的token,
  • 得到token就可以让其继续执行,否则返回false:不允许进行
package com.example.day724test.intercepor;

import com.example.day724test.Utils.JwtUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;


@Component
public class LoginInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求头中的token
        String token = request.getHeader("Authorization");
        // 判断token是否为空,如果为空表示未登录,返回登录页面
        try {
            Map<String, Object> claims = JwtUtil.parseToken(token);
            /*
            放行
             */
            return true;
        }catch (Exception e){
            return false;
            /*
            不放行
             */
        }
    }
}

此外,定义

WebConfig类
 选择性过滤掉login,register  这两种接口外的其它接口需要实现登录验证
package com.example.day724test.config;

import com.example.day724test.intercepor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Component
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //登录接口和注册接口不拦截
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
    }
}

修改原来的Controller逻辑:

   @GetMapping("/all")
   public Result<String> getAllUser(@RequestHeader("Authorization") String token, HttpServletRequest response){ //请求头中获取token
//       try {
//           Map<String, Object> claims = JwtUtil.parseToken(token);
//           return Result.success("所有的文章数据");
//       }catch (Exception e){
//           return Result.error("未登录");
//       }
       return Result.success("所有的文章数据,,,,,,,,,");
   }

来进行测试:

直接访问/user/all:

携带token之后:

请求成功:基本的登录验证已经完成

项目保存的gitee地址:gitee地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值