SpringSecurity认证鉴权流程

  • SpringSecurity的认证流程

    • 用户请求

      • 用户向应用程序发起请求,通常是访问受保护的资源(例如,一个需要登录的页面)。
    • 检查是否需要认证

      • Spring Security会检查请求的URL是否需要认证。这个检查是基于配置的访问控制规则来决定的。配置类要继承WebSecurityConfigurerAdapter
    • 触发认证

      • 如果请求的资源需要认证,Spring Security会将用户重定向到登录页面(如果未认证),或者直接处理认证(如果用户已经在认证上下文中)。
    • 认证请求

      • 用户在登录表单中输入凭据(如用户名和密码),这些凭据会被提交到Spring Security的认证处理器。
    • 处理认证

      • Spring Security的认证处理器(UsernamePasswordAuthenticationFilter 是默认的处理器),UsernamePasswordAuthenticationFilter会创建一个Authentication接口的实现类对象(UsernamePasswordAuthenticationToken)来接收到用户提交的凭据。
      • 处理器会使用认证管理器(AuthenticationManager)来验证凭据。认证管理器会将请求传递给配置的认证提供者(AuthenticationProvider–可以在配置类中启用我们自己的认证提供者)。
    • 认证提供者验证

      • 认证提供者(如DaoAuthenticationProvider)会从UsernamePasswordAuthenticationToken中拿到并验证用户提交的凭据。这通常涉及查找用户的记录,并检查密码是否匹配。
      • 认证提供者通过用户详细信息服务(UserDetailsService)加载用户的详细信息,然后进行密码验证。
    • 返回认证结果

      • 如果凭据有效,认证提供者会返回一个包含用户认证信息的Authentication(其实就是实现了Authentication接口的UsernamePasswordAuthenticationToken对象)对象。
      • 如果凭据无效,认证提供者会抛出一个认证异常(例如BadCredentialsException)。
    • 更新安全上下文

      • 认证管理器会将返回的Authentication对象存储在Spring Security的SecurityContext中。
      • SecurityContext存储在SecurityContextHolder中,以便在整个请求的生命周期内可以访问到认证信息。
    • 处理认证后的请求

      • 如果认证成功,用户会被重定向到他们最初请求的页面,或者根据配置被重定向到一个默认的成功页面/处理器。
      • 如果认证失败,用户会被重定向到登录页面/处理器,并显示适当的错误消息。
    • 权限检查

    • 认证成功后,Spring Security还会基于配置的权限规则来检查用户是否有权限访问请求的资源。这通常发生在请求被处理的阶段。

  • SpringSecurity的鉴权流程

    • 权限检查阶段
      • FilterSecurityInterceptor: 这是负责进行授权检查的主要过滤器。它会从 SecurityContext 中获取当前用户的 Authentication 对象,并使用其中的权限集合(即 getAuthorities 方法返回的集合)来决定是否允许访问特定资源。
      • AccessDecisionManager: FilterSecurityInterceptor 使用 AccessDecisionManager 来做出最终的访问决策。AccessDecisionManager 会将用户的权限集合与配置的访问控制规则进行比较,决定是否允许访问。
    • 权限投票
      • AccessDecisionVoter: 这个组件对用户是否有访问权限进行投票。它会检查用户的权限集合来决定是否允许访问请求的资源。AccessDecisionVoter 可以是基于角色、权限或自定义逻辑的投票器。
    • 访问决策
      • AccessDecisionManager 会根据所有 AccessDecisionVoter 的投票结果来做出最终的决策。如果所有投票者都允许访问,则用户可以访问请求的资源;否则,访问会被拒绝。
  • 将用户交给Spring Security管理主要涉及以下几个步骤:

    • 实现 UserDetails 接口

      • 创建一个自定义的 UserDetails 实现类,用于封装用户的详细信息,包括用户名、密码和权限等。
      public class CustomUserDetails implements UserDetails {
          private final User user; // 你的用户实体
          private final Collection<? extends GrantedAuthority> authorities;
      
          public CustomUserDetails(User user) {
              this.user = user;
              this.authorities = user.getRoles().stream()
                  .map(role -> new SimpleGrantedAuthority(role.getCode()))
                  .collect(Collectors.toList());
          }
      
          @Override
          public Collection<? extends GrantedAuthority> getAuthorities() {
              return authorities;
          }
      
          @Override
          public String getPassword() {
              return user.getPassword();
          }
      
          @Override
          public String getUsername() {
              return user.getUsername();
          }
      
          @Override
          public boolean isAccountNonExpired() {
              return true;
          }
      
          @Override
          public boolean isAccountNonLocked() {
              return true;
          }
      
          @Override
          public boolean isCredentialsNonExpired() {
              return true;
          }
      
          @Override
          public boolean isEnabled() {
              return user.isEnabled();
          }
      }
      
    • 实现 UserDetailsService 接口

      • 创建一个 UserDetailsService 实现类,用于根据用户名加载用户的 UserDetails 实例。
      @Service
      public class CustomUserDetailsService implements UserDetailsService {
          @Autowired
          private UserRepository userRepository;
      
          @Override
          public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
              User user = userRepository.findByUsername(username);
              if (user == null) {
                  throw new UsernameNotFoundException("User not found");
              }
              return new CustomUserDetails(user);
          }
      }
      
    • 配置 Spring Security

      • 在Spring Security配置中,将 UserDetailsService 注册为一个bean,并配置认证管理器使用这个服务来进行用户认证。
      @Configuration
      @EnableWebSecurity
      public class SecurityConfig extends WebSecurityConfigurerAdapter {
          @Autowired
          private CustomUserDetailsService userDetailsService;
      
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
          }
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests()
                      .anyRequest().authenticated()
                  .and()
                  .formLogin()
                      .loginPage("/login")
                      .permitAll()
                  .and()
                  .logout()
                      .permitAll();
          }
      }
      
    • 配置密码编码器

      • 使用 BCryptPasswordEncoder 或其他密码编码器来处理用户密码的加密和验证(可以在实现了WebSecurityConfigurerAdapter的配置类中注册)。
      @Bean
      public PasswordEncoder passwordEncoder() {
          return new BCryptPasswordEncoder();
      }
      
  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JH3073

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

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

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

打赏作者

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

抵扣说明:

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

余额充值