第四节 springsecurity结合jwt实现前后端分离开发

本文档详细介绍了如何使用SpringBoot、MybatisPlus、SpringSecurity和JWT实现后台管理系统,包括用户登录、权限控制、JWT token的生成与验证、缓存策略、消息队列、日志管理和数据库定时备份等。还提到了在SpringSecurity中整合JWT的一些问题及解决方案,如处理登录过滤、验证过滤以及在无token情况下清空认证。提供了完整的代码示例和测试流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

svbadmin学习日志

本学习日志是使用Springboot和Vue来搭建的后台管理系统:
演示地址:http://118.31.68.110:8081/index.html
账号:root
密码:123
所有代码可以在gitbub上找到,切换到相应分支即可。【代码传送门

正篇

第一节 spring boot 模块化构建项目
第二节 整合mybatisplus完成用户增删改查
第三节 整合springsecurity实现基于RBAC的用户登录
第四节 springsecurity结合jwt实现前后端分离开发
第五节 使用ResponseBodyAdvice格式化接口输出
第六节 springboot结合redis实现缓存策略
第七节 springboot结合rabbitmq实现队列消息
第八节 springboot结合rabbitmq实现异步邮件发送
第九节 利用springboot的aop实现行为日志管理
第十节 利用Quartz实现数据库定时备份
第十一节 springboot配置log输出到本地文件
第十二节 使用flyway对数据库进行版本管理
第十三节 springboot配合VbenAdmin实现前端登录
第十四节 springboot配合VbenAdmin实现用户CURD
第十五节 基于RBAC的权限管理VbenAdmin前端实现
第十六节 springboot 打包vue代码实现前后端统一部署

番外

2.1 数据库设计原则
3.1 配置apifox自动获取登录的token
13.1 springboot 全局捕捉filter中的异常
14.1 springsecurity整合mybatisplus出现isEnable的问题和解决方案


前言

前后端分离现在是主流开发形式,jwt也是用的比较多一种令牌方式,接下来我们来整合下jwt。方便后续和vue进行前后端联动开发。


一、加入jwt依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

二、创建jwt处理类

1.处理登录的类 JwtLoginFilter

public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {
    protected JwtLoginFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {
        super(new AntPathRequestMatcher(defaultFilterProcessesUrl));
        setAuthenticationManager(authenticationManager);
    }
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse resp) throws AuthenticationException, IOException, ServletException, IOException {
        User user = new ObjectMapper().readValue(req.getInputStream(), User.class);
        return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
    }
    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse resp, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities();
        StringBuffer as = new StringBuffer();
        for (GrantedAuthority authority : authorities) {
            as.append(authority.getAuthority())
                    .append(",");
        }
        String jwt = Jwts.builder()
                .claim("authorities", as)//配置用户角色
                .setSubject(authResult.getName())
                .setExpiration(new Date(System.currentTimeMillis() + 10 * 60 * 1000))
                .signWith(SignatureAlgorithm.HS512,"sang@123")
                .compact();
        resp.setContentType("application/json;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.write(new ObjectMapper().writeValueAsString(jwt));
        out.flush();
        out.close();
    }
    protected void unsuccessfulAuthentication(HttpServletRequest req, HttpServletResponse resp, AuthenticationException failed) throws IOException, ServletException {
        resp.setContentType("application/json;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.write("登录失败!");
        out.flush();
        out.close();
    }
}

2.处理验证的类 JwtFilter

public class JwtFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        String jwtToken = req.getHeader("authorization");
        System.out.println(jwtToken);
        if (jwtToken != null){
            Claims claims = Jwts.parser().setSigningKey("sang@123").parseClaimsJws(jwtToken.replace("Bearer",""))
                    .getBody();
            String username = claims.getSubject();//获取当前登录用户名
            List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities"));
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, null, authorities);
            SecurityContextHolder.getContext().setAuthentication(token);
        }else{
	            SecurityContextHolder.getContext().setAuthentication(null); // 如果没有token,则清空认证,否则会使用上一次缓存的token
        }
        filterChain.doFilter(req,servletResponse);
    }
}

3.修改SecurityConfiguration

...              
.addFilterBefore(new JwtLoginFilter("/login",authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JwtFilter(),UsernamePasswordAuthenticationFilter.class)
...

三、测试

未登录的情况下,访问接口

这里显示的是403,当然可以自定义成401。具体可直接下载代码体验。
在这里插入图片描述

login 登录返回token

在这里插入图片描述

使用返回的token, 放入到auth中继续请求其他接口

在这里插入图片描述


总结

  1. Security 整合jwt 有很多种方法, 核心还是要理解filterChain
  2. 目前的返回格式比较不符规范,下一节把输出格式化下

问题

  1. 如果第一次带token访问,第二次删除token直接访问,竟然直接成功了。于是我加了行判断,把token置空。 就是以下这段代码:
SecurityContextHolder.getContext().setAuthentication(null); // 如果没有token,则清空认证,否则会使用上一次缓存的token

这不知道有没有更好的解决方法,大家可以留言探讨下。


代码地址

代码


参考文档:
干货|一个案例学会Spring Security 中使用 JWT
整合SpringSecurity和JWT实现登录认证和授权

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

F_angT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值