SpringBoot - SpringSecurity结合JWT的身份验证及动态权限解决方案

本文介绍了如何使用SpringBoot结合SpringSecurity和JWT实现身份验证及动态权限控制。详细阐述了登录认证阶段、授权阶段的流程,包括账号密码验证、JWT token的创建和权限管理。同时,提到了注销阶段、未授权处理的处理方法,以及SpringSecurity配置的核心代码。提供了一个基于SpringBoot的JWT和SpringSecurity认证授权Demo的下载链接。
摘要由CSDN通过智能技术生成

花了点时间写了一个SpringSecurity集合JWT完成身份验证的Demo,并按照自己的想法完成了动态权限问题。在写这个Demo之初,使用的是SpringSecurity自带的注解权限,但是这样权限就显得不太灵活,在实现之后,感觉也挺复杂的,欢迎大家给出建议。Demo下载地址,见文末。

JWT是什么可以参考我另一篇博文:浅谈JWT身份认证及其优缺点

认证流程及授权流程

我画了个建议的认证授权流程图,后面会结合代码进行解释整个流程。
在这里插入图片描述

一、登录认证阶段

实现SpringSecurity的UsernamePasswordAuthenticationFilter接口(public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter),在它的实现类的构造方法里设置登录的请求路径和请求方式。

this.setPostOnly(false);
// 认证路径 - 发送什么请求,就会进行认证
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/service_auth/admin/index/login","POST"));

当前端发起配置的请求时,请求会被拦截,进入到attemptAuthentication方法进行验证,在这个方法里可以从request中取出账号、密码,从而调用AuthenticationManagerauthenticate去校验账号、密码是否正确。

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
        throws AuthenticationException {
   
    try {
   
        User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
        // 也可以直接获取账号密码
        String username = obtainUsername(request);
        String password = obtainPassword(request);
        log.info("TokenLoginFilter-attemptAuthentication:尝试认证,用户名:{}, 密码:{}", username, password);
        // 在authenticate里去进行校验的,校验过程中会去把UserDetailService里返回的SecurityUser(UserDetails)里的账号密码和这里传的账号密码进行比对
        // 并在UserDetailService里将权限进行赋予
        // 校验通过,会进入到successfulAuthentication方法
        return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
    } catch (IOException e) {
   
        throw new RuntimeException(e);
    }
}
那么这个authenticate方法是怎么验证我们账号密码正确性的呢?

打上断点,跟随源码,我们进入到authenticate方法内部:
在这里插入图片描述
然后进入这个方法内部,继续往下走,看到一段核心代码:
在这里插入图片描述
进入retrieveUser方法里,然后往下走,看到一句核心代码,这个核心代码就是获取用户信息的:
在这里插入图片描述
这里注意,调用了UserDetailsServiceloadUserByUsername方法,传入的就是前端传过来的username,意思就是要根据这个username去获取UserDetails对象,所以我们就要去查询数据库,所以我们就要实现UserDetailsService接口并重写loadUserByUsername方法。

@Service("userDetailsService")
@Slf4j
public class UserDetailServiceImpl implements UserDetailsService {
   
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
   
        log.info("根据username去数据库查询用户信息,username:{}", username);
        // 1、从数据库中取出用户信息 - 这里模拟,直接new一个User对象
        User user = new User();
        user.setUsername(username);
        // 111111经过加密后
        user.setPassword("96e79218965eb72c92a549dd5a330112");
        SecurityUser securityUser = new SecurityUser(user);
        // 可以根据查出来的user.getId()去查询这个用户对应的权限集合 - 这里模拟,直接new一个结合
        List<String> authorities = new ArrayList<>();
        // 将权限赋予用户
        securityUser.<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值