看的是B站三更草堂的课,包括下面的笔记基本上也都整理自UP给出的资料

SpringSecurity完整流程

图中只展示了核心过滤器,其它的非核心过滤器并没有在图中展示

  • UsernamePasswordAuthenticationFilter
    • 处理登陆页面用户名密码的登陆请求
  • ExceptionTranslationFilter
    • 处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException
  • FilterSecurityInterceptor
    • 负责权限校验的过滤器

image-20230417211028922

思路分析

  • 登录

    • 自定义登录接口

      • 调用ProviderManager的方法进行认证 如果认证通过生成jwt

      • 把用户信息存入redis中

      • 自定义UserDetailsService

      • 在这个实现类中去查询数据库

  • 校验

    • 定义Jwt认证过滤器

      • 获取token

      • 解析token获取其中的userid

      • 从redis中获取用户信息

      • 存入SecurityContextHolder

工具类

添加工具配置类

image-20230418202050614

实现

核心代码实现

创建一个类实现UserDetailsService接口,重写其中的方法

@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName,username);
        User user = userMapper.selectOne(queryWrapper);
        if (Objects.isNull(user)){
            throw new RuntimeException("用户名不存在");
        }
        return new LoginUser(user);
    }
}

因为UserDetailsService方法的返回值是UserDetails类型,所以需要定义一个类,实现该接口,把用户信息封装在其中

@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {
    private User user;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

密码加密储存

默认使用的PasswordEncoder要求数据库中的密码格式为:{id}password

我们只需要使用把BCryptPasswordEncoder对象注入Spring容器中,SpringSecurity就会使用该PasswordEncoder来进行密码校验

我们可以定义一个SpringSecurity的配置类,继承WebSecurityConfigurerAdapter

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

未完待续…

后续

SpringSecurity学习笔记