SpringSecurity认证鉴权流程
-
SpringSecurity的认证流程
-
用户请求:
- 用户向应用程序发起请求,通常是访问受保护的资源(例如,一个需要登录的页面)。
-
检查是否需要认证:
- Spring Security会检查请求的URL是否需要认证。这个检查是基于配置的访问控制规则来决定的。配置类要继承WebSecurityConfigurerAdapter
-
触发认证:
- 如果请求的资源需要认证,Spring Security会将用户重定向到登录页面(如果未认证),或者直接处理认证(如果用户已经在认证上下文中)。
-
认证请求:
- 用户在登录表单中输入凭据(如用户名和密码),这些凭据会被提交到Spring Security的认证处理器。
-
处理认证:
- Spring Security的认证处理器(
UsernamePasswordAuthenticationFilter
是默认的处理器),UsernamePasswordAuthenticationFilter会创建一个Authentication接口的实现类对象(UsernamePasswordAuthenticationToken)来接收到用户提交的凭据。 - 处理器会使用认证管理器(
AuthenticationManager
)来验证凭据。认证管理器会将请求传递给配置的认证提供者(AuthenticationProvider
–可以在配置类中启用我们自己的认证提供者)。
- Spring Security的认证处理器(
-
认证提供者验证:
- 认证提供者(如
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(); } }
- 在Spring Security配置中,将
-
配置密码编码器:
- 使用
BCryptPasswordEncoder
或其他密码编码器来处理用户密码的加密和验证(可以在实现了WebSecurityConfigurerAdapter的配置类中注册)。
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
- 使用
-