架构:https://spring.io/guides/topicals/spring-security-architecture
文档:https://docs.spring.io/spring-security/site/docs/5.3.13.RELEASE/reference/html5/
谈到应用安全框架就离不开两个核心功能:认证(Authentication)、授权(Authorization)。
认证授权常用的认证方式就是通过用户名和密码进行登录,
那用户登录时,就需要获取系统中已有的用户信息进行验证,比如检查密码是否匹配、用户状态是否正常等,
如果验证通过,那表示登录成功,则考虑返回cookie或者token,如果验证失败,那就需要返回相应的提示信息;
有登录自然就有了登出,登出后自然需要返回相应的提示信息。
整个流程下来,就需要不同的功能组件配合,包括:登录接口、用户信息查询、密码验证、认证成功处理、认证失败处理、登出接口、登出失败处理。
Spring Security 对于诸多功能点都抽象为接口,以实现灵活的扩展。
就比如用户信息查询功能,在认证的时候可能只需要用户名和密码,但框架不关注你从哪里获取到这些信息,可以从内存中,可以从数据库中等等,所以,将用户信息查询功能抽象成一个接口,方法只需要返回用户名和密码,至于实现可自由扩展。
下面我们就开始一一说明 Spring Security 对上述的功能点是如何设计的。
Spring Security设计了 UsernamePasswordAuthenticationFilter 过滤器来提供登录接口,请求路径为 POST /login,请求字段为 username、password。
Spring Security设计了 UserDetailsService 接口用于获取用户信息,其接口定义如下:
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
loadUserByUsername 方法用于通过用户名获取用户信息。
还有一个值得关注的点就是方法的返回值是 UserDetails。
UserDetails定义了在认证系统中需要的用户信息的最小子集,这些信息足以完成认证流程,而不需要关注使用者的用户表设计有多少个字段。
就比如说,只需要用户名和密码就能做认证了,像是年龄身高体重这些和认证完全不搭边的可以不关注。实际上UserDetails没那么简单,它还设计了像过期、锁定等功能,其接口定义如下:
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
Spring Security设计了 PasswordEncoder 接口来对密码进行加密和验证,其接口定义如下:
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
}
encode 方法用于将明文密码加密成密文。一般是在存储用户密码前进行加密保存。
matches 方法用于验证明文密码和密文是否一致。一般是用在用户登录时,验证输入的明文密码和存储的密文是否一致。
Spring Security设计了 AuthenticationSuccessHandler 接口来定义认证成功后的处理逻辑,其接口定义如下:
public interface AuthenticationSuccessHandler {
void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException;
}
Spring Security设计了 AuthenticationFailureHandler 接口来定义认证失败后的处理逻辑,其接口定义如下:
public interface AuthenticationFailureHandler {
void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException;
}
Spring Security设计了 LogoutFilter 过滤器来提供登出接口,请求路径为 POST /logout。
Spring Security设计了 LogoutSuccessHandler 接口来定义登出成功后的处理逻辑,其接口定义如下:
public interface LogoutSuccessHandler {
void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException;
}
end