过滤器链
SpringSecurity本质是一个过滤器链:从启动是可以获取到过滤器链:
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
org.springframework.security.web.context.SecurityContextPersistenceFilter
org.springframework.security.web.header.HeaderWriterFilter
org.springframework.security.web.csrf.CsrfFilter
org.springframework.security.web.authentication.logout.LogoutFilter
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter
org.springframework.security.web.savedrequest.RequestCacheAwareFilter
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
org.springframework.security.web.session.SessionManagementFilter
org.springframework.security.web.access.ExceptionTranslationFilter
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
一个方法级的权限过滤器,基本位于过滤器链的最底部
此类实现了Filter接口,说明是一个过滤器
在doFilter()方法中执行了invoke()方法
异常过滤器,用来处理在认证授权过程中抛出的异常
在doFilter()方法中放行,在handleSpringSecurityException()方法中对不同的异常进行处理
对/login的POST请求做拦截,校验表单中用户名和密码。attemptAuthentication()方法根据post请求中的用户名密码进行校验
往上看,UsernamePasswordAuthenticationFilter类是继承了抽象类AbstractAuthenticationProcessingFilter在抽象类AbstractAuthenticationProcessingFilter中可以看到两个方法,上面的方法是用户名和密码认证成功后执行的代码,下面的则是认证失败执行的代码,所以在UsernamePasswordAuthenticationFilter过滤器中,登录认证成功或失败都会默认调用父类的方法
过滤器加载过程
使用SpringSecurty配置过滤器,也就是SpringBoot项目中自动配置的DelegatingFilterProxy类而在doFilter()方法各种判断过后调用了initDelegate()方法,在该方法里可以获取到FilterChainProxy对象在FilterChainProxy也会进入doFilter()方法,然后再进行各种判断后,会进入doFilterInternal()方法而在doFilterInternal()方法中会将过滤器链中的过滤器加载进来,进行逐个执行
两个重要的接口
当什么也没有配置的时候,账号和密码是由SpringSecurity定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。所以要通过自定义逻辑控制认证逻辑。
如果需要自定义逻辑时,只需要实现UserDetailsService接口即可。
在UserDetailsService接口中只有一个方法loadUserByUsername()。
该方法的返回值是UserDetails接口的实现类对象,这个类是系统默认的用户“主体”,在SpringSecurity有一个UserDetails接口的实现类,类名就叫User。该方法的参数username,表示用户名。此值是客户端表单传递过来的数据。默认情况下必须叫username,否则无法接收。
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
使用该接口的步骤则是:
创建类继承UsernamePasswordAuthenticationFilter过滤器,并且重写该类中的三个方法(doFilter方法,认证成功的方法,认证失败的方法)创建类实现UserDetailsService,编写查询数据的过程,返回User对象(该对象是SpringSecurity提供的对象)
数据加密接口,用于返回User对象里面密码加密,而BCryptPasswordEncoder类是PasswordEncoder的实现类。
BCryptPasswordEncoder是SpringSecurity官方推荐的密码解析器,平时多使用这个解析器。BCryptPasswordEncoder是对bcrypt强散列方法的具体实现。是基于Hash算法实现的单向加密。可以通过strength控制加密强度,默认10.
具体使用方法可以我的主页搜索BCryptPasswordEncoder
文章为作者独立观点,不代表观点