表单登录
UsernamePasswordAuthenticationFilter
/login Post 请求
会被这个过滤器拦截
如果为/login时 会经过
if (!this.requiresAuthentication(request, response))
判断是否和设置的loginProcessingUrl一致
此时 由相应的AuthenticationProvider(这里是DaoAuthenticationProvider)匹配Authentication,如果support()
可以自定义provider给ProviderManager:
在webconfig中重写
@Override
protected AuthenticationManager authenticationManager() throws Exception {
ProviderManager authenticationManager = new ProviderManager(Arrays.asList(inMemoryAuthenticationProvider,daoAuthenticationProvider()));
//不擦除认证密码,擦除会导致TokenBasedRememberMeServices因为找不到Credentials再调用UserDetailsService而抛出 UsernameNotFoundException
authenticationManager.setEraseCredentialsAfterAuthentication(false);
return authenticationManager;
}
AbstractUserDetailsAuthenticationProvider
内置了缓存机制,从缓存中获取不到的 UserDetails 信息的话,就调用如下方法获取用户信息,然后和 用户传来的信息进行对比来判断是否验证成功。
验证:provider.authenticate(authentication),进入retrieveUser()
开始调用
UserDetailsService().loadUserByUsername(username);
根据username查出整个user
和之前的authentication
调用 this.additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken)authentication);
验证成功后
然后通过
this.getRedirectStrategy().sendRedirect(request, response, targetUrl);
重定向,故在此进入filter
整个最基本的流程图:
spring security 加密 ,这里使用
BCryptPasswordEncoder
BCryptPasswordEncoder
使用BCrypt的强散列哈希加密实现,并可以由客户端指定加密的强度strength
,强度越高安全性自然就越高,默认为10.
特点:每一次hash都自动生成不同的盐,并将盐值放在hash值中
security 核心-------过滤器链
- SecurityContextPersistenceFilter: 整个Spring Security 过滤器链的开端,它有两个作用:一是当请求到来时,检查
Session
中是否存在SecurityContext
,如果不存在,就创建一个新的SecurityContext
。二是请求结束时将SecurityContext
放入Session
中,并清空SecurityContextHolder
。 - UsernamePasswordAuthenticationFilter: 继承自抽象类
AbstractAuthenticationProcessingFilter
,当进行表单登录时,该Filter将用户名和密码封装成一个UsernamePasswordAuthentication
进行验证。 - AnonymousAuthenticationFilter: 匿名身份过滤器,当前面的Filter认证后依然没有用户信息时,该Filter会生成一个匿名身份——
AnonymousAuthenticationToken
。一般的作用是用于匿名登录。 - ExceptionTranslationFilter: 异常转换过滤器,用于处理
FilterSecurityInterceptor
抛出的异常。 - FilterSecurityInterceptor: 过滤器链最后的关卡,从 SecurityContextHolder中获取 Authentication,比对用户拥有的权限和所访问资源需要的权限。
SecurityContextPersistenceFilter
请求先经过 SecurityContextPersistenceFilter
过滤器,在前面就曾提到,该Filter有两个作用,其中之一就是在请求到来时,创建 SecurityContext
安全上下文,我们来看看它内部是如何做的,部分源码如下:
我们这里是第一次请求,读取的安全上下文中是没有 Authentication
身份信息的,将安全上下文设置到 SecurityContextHolder
之后,进入下一个过滤器。
UsernamePasswordAuthenticationFilter
经过 SecurityContextPersistenceFilter
过滤器后来到 UsernamePasswordAuthenticationFilter
过滤器,因为我们假定的是第一次请求,所以 SecurityContext
并没有包含认证过的 Authentication
。从此过滤器开始的操作对于表单登录来说是非常关键的,包含了表单登录的核心认证步骤
UsernamePasswordAuthenticationFilter
的父类是 AbstractAuthenticationProcessingFilter
,首先进入父类的 foFilter
方法
具体都在跟上面说的一样
AnonymousAuthenticationFilter
匿名认证过滤器,它主要是针对匿名登录,如果前面的Filter,比如UsernamePasswordAuthenticationFilter
执行完毕后,SecurityContext依旧没有用户信息,那么AnonymousAuthenticationFilter
才会起作用,生成一个匿名身份信息——AnonymousAuthenticationToken
ExceptionTranslationFilter
ExceptionTranslationFilter
简单的说就是处理 FilterSecurityInterceptor 抛出的异常,其内部doFilter
方法源码如下:
FilterSecurityInterceptor
FilterSecurityInterceptor
过滤器是最后的关卡,之前的请求最终会来到这里,它的大致工作流程就是
- 封装请求信息
- 从系统中读取配信息,即资源所需的权限信息
- 从
SecurityContextHolder
中获取之前认证过的Authentication
对象,即表示当前用户所拥有的权限 - 然后根据上面获取到的三种信息,传入一个权限校验器中,对于当前请求来说,比对用户拥有的权限和资源所需的权限。若比对成功,则进入真正系统的请求处理逻辑,反之,会抛出相应的异常
使用第三方登录(github登录)
加入过滤器
IntegrationAuthenticationFilter(自己写的)
当符合/oauth/github时,不执行chain.doFileter,直接重定向
下面是spring security的源码 也是类似的处理方式