在Spring boot中 使用JWT和过滤器实现登录认证

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 在Spring boot中 使用JWT和过滤器实现登录认证

在Spring boot中 使用JWT和过滤器实现登录认证

一、登录获得JWT

  1. 在navicat中运行如下sql,准备一张user表
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` int(11) NOT NULL,
  `username` varchar(50) NOT NULL,
  `password` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES ('1', 'root', '123', '1');
  1. 导入pom.xml坐标
<!-- JWT依赖坐标-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
    <!-- 解析JSON-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.15.2</version>
        </dependency>
  1. 在工utils包下创建一个用于生成和解析JWT 令牌的工具类
public class JwtUtils {
    private static String signKey = "baisepengyuyan";//签名密钥(这个可以自定义)
    private static Long expire = 86400000L; //有效时间 1 天 = 24 小时 * 60 分钟 * 60 秒 * 1000 毫秒 = 86,400,000 milliseconds
    /*生成JWT令牌*/
    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)//自定义信息(有效载荷)
                .signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部)
                .setExpiration(new Date(System.currentTimeMillis() + expire))//过期时间
                .compact();
        return jwt;
    }
    /*解析JWT令牌 */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)//指定签名密钥
                .parseClaimsJws(jwt)//指定令牌Token
                .getBody();
        return claims;    //返回令牌中 payload 中存储的内容(登录用户的信息)
    }
}
  1. 在pojo包下创建user类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private String username;
    private String password;
}
  1. 在mapper包下添加 UserMapper接口
@Mapper
public interface UserMapper {
    @Select("select id ,username ,password from t_user where username = #{username} and password= #{password}")
    User getLoginUser(User user);
}
  1. 在service包下添加 UserService类
@Service
public class UserService {
    @Autowired
    UserMapper userMapper;
    public User login(User user) {
        User loginUser = userMapper.getLoginUser(user);
        if (loginUser == null )
            return null;
        return user;
    }
}
  1. 在utils包下添加统一响应结果封装类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Integer code ;//1 成功 , 0 失败
    private String msg; //提示信息
    private Object data; //数据 data
    public static Result success(Object data){
        return new Result(1, "success", data);
    }
    public static Result success(){
        return new Result(1, "success", null);
    }
    public static Result error(String msg){
        return new Result(0, msg, null);
    }
    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}
  1. 在controller包下添加LoginController类
@RestController
@Slf4j
public class LoginController {
    //依赖业务层对象
    @Autowired
    private UserService userService;
    @PostMapping("/login")
    public Result login(@RequestBody User user) {
        //调用业务层:登录功能
        User loginEmp = userService.login(user);
        //判断:登录用户是否存在
        if(loginEmp !=null ){
            //自定义信息
            Map<String , Object> claims = new HashMap<>();
            claims.put("id", loginEmp.getId());
            claims.put("username",loginEmp.getUsername());
            claims.put("name",loginEmp.getName());
            //使用JWT工具类,生成身份令牌
            String token = JwtUtils.generateJwt(claims);
            return Result.success(token);
        }
        return Result.error("用户名或密码错误");
    }
}

这样登录获取token的接口就写好了,接下来我们来用post工具来测一下这个登录接口

这里我使用的工具是Apifox

这样我们就拿到了 这个token (这个token的有效期是一天, 有效时间的长短可以在JWT工具类那里设置)

eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpudWxsLCJpZCI6MCwidXNlcm5hbWUiOiJtYWkiLCJleHAiOjE2OTg2NTg1OTh9.aFDGnKvMOjgpZjdgXcQfaDM1ONupOvdwYtYNxPAaN6s

这样我们就将这个登录获取JWT的功能开发好了,但是, 现在我们仍然可以访问别的请求路径,不被拦截,所以我们要引入过滤器.

二、引入过滤器

引入过滤器的就是为了,限制为未登录的用户。不让他们访问除了登录以外的资源。

那现在我们写一个测试用例,用于测试, 看看没引入过滤器和引入过滤器的区别

  • 在LoginController类下添加这个方法
@GetMapping("/getResource")
    public Result getUser(){
        return Result.success("成功访问/getResource");
    }

添加完这个方法后 我们尝试访问 http://localhost:8080/getResource

这是我们可以看到用户在未登录的情况下, 仍然可以正常访问我们的资源, 这是我们不希望看到的.

那么我们开始引入过滤器

  1. 在启动类上添加 @ServletComponentScan注解
@ServletComponentScan
  1. 创建一个filter包 ,在这个包下创建 LoginCheckFilter类
@Slf4j
@WebFilter(urlPatterns = "/*") //拦截所有请求
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        //前置:强制转换为http协议的请求对象、响应对象 (转换原因:要使用子类中特有方法)
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        //创建json解析对象
        ObjectMapper objectMapper = new ObjectMapper();
        //1.获取请求url
        String url = request.getRequestURL().toString();
        log.info("请求路径:{}", url); //请求路径:http://localhost:8080/login
        //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行
        if(url.contains("/login")){
            chain.doFilter(request, response);//放行请求
            return;//结束当前方法的执行
        }
        //3.获取请求头中的令牌(token)
        String token = request.getHeader("Authorization");
        log.info("从请求头中获取的令牌:{}",token);
        //4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
        if(!StringUtils.hasLength(token)){
            log.info("Token不存在");
            Result responseResult = Result.error("NOT_LOGIN");
            //把Result对象转换为JSON格式字符串
            String json = objectMapper.writeValueAsString(responseResult);
            response.setContentType("application/json;charset=utf-8");
            //响应
            response.getWriter().write(json);
            return;
        }
        //5.解析token,如果解析失败,返回错误结果(未登录)
        try {
            if (token.startsWith("Bearer ")) {
                token = token.substring(7);
                log.info("切除Bearer 令牌:{}",token);
            }
            JwtUtils.parseJWT(token);
        }catch (Exception e){
            log.info("令牌解析失败!");
            Result responseResult = Result.error("NOT_LOGIN");
            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = objectMapper.writeValueAsString(responseResult);
            response.setContentType("application/json;charset=utf-8");
            //响应
            response.getWriter().write(json);
            return;
        }
        //6.放行
        chain.doFilter(request, response);
    }
}

阅读代码我们可以发现, 我们拦截了所有请求,唯独给登录请求放行

现在我们再来尝试访问

但是新的问题来了 , 我们要怎么访问这个资源呢? 对, 使用刚刚我们登录后返回的JWT令牌

我们在每次请求时都在HTTP的请求头中携带JWT令牌过去

访问 http://localhost:8080/login 获得令牌

拿到令牌后 我们访问http://localhost:8080/getResource

在请求中 添加Authorization请求头 值为 Bearer + 空格 + JWT

我们可以看到 在实际的请求总 我们多谢了一个请求头 请求头和请求参数是不一样的!!!

到此 我们已经完成了一个Spring Boot整合JWT和过滤器 完成登录验证的功能了.


相关文章
|
1月前
|
安全 Java 数据库
安全无忧!在 Spring Boot 3.3 中轻松实现 TOTP 双因素认证
【10月更文挑战第8天】在现代应用程序开发中,安全性是一个不可忽视的重要环节。随着技术的发展,双因素认证(2FA)已经成为增强应用安全性的重要手段之一。本文将详细介绍如何在 Spring Boot 3.3 中实现基于时间的一次性密码(TOTP)双因素认证,让你的应用安全无忧。
81 5
|
26天前
|
JSON 安全 算法
|
26天前
|
存储 安全 Java
|
1月前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
24 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
1月前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
15天前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
30 0
|
1月前
|
存储 JSON 算法
JWT令牌基础教程 全方位带你剖析JWT令牌,在Springboot中使用JWT技术体系,完成拦截器的实现 Interceptor (后附源码)
文章介绍了JWT令牌的基础教程,包括其应用场景、组成部分、生成和校验方法,并在Springboot中使用JWT技术体系完成拦截器的实现。
72 0
JWT令牌基础教程 全方位带你剖析JWT令牌,在Springboot中使用JWT技术体系,完成拦截器的实现 Interceptor (后附源码)
|
1月前
|
JavaScript
Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(二)
Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(一)
31 0
|
1月前
|
存储 JSON JavaScript
Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(一)
Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(一)
85 0
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
145 1