这是一个泛型接口,泛型参数O来表示所要配置的安全构建器要构建的目标对象类型(O可以理解成是Output的缩写)。泛型参数B表示当前安全配置器所要初始化和配置的安全构建器类型(B可以理解成是Builder的缩写)。
首先会进入 UsernamePasswordAuthenticationFilter 并且设置权限为null和是否授权为false,然后进入 ProviderManager 查找支持 UsernamepasswordAuthenticationToken 的 provider 并且调用 providerauthenticate(authentication); 再然后就是 UserDetailsService 接口的实现类(也就是自己真正具体的业务了),这时候都检查过了后,就会回调 UsernamePasswordAuthenticationFilter 并且设置权限(具体业务所查出的权限)和设置授权为true(因为这时候确实所有关卡都检查过了)。
UsernamePasswordAuthenticationFilter
可以发现继承了 AbstractAuthenticationProcessingFilter ,那我们就来看下此类
1、继承了父类,父类是个过滤器,所以肯定先执行 AbstractAuthenticationProcessingFilterdoFilter() ,此方法首先判断当前的filter是否可以处理当前请求,不可以的话则交给下一个filter处理。
2、调用此抽象类的子类 UsernamePasswordAuthenticationFilterattemptAuthentication(request, response) 方法做具体的 *** 作。
3、最终认证成功后做一些成功后的 session *** 作,比如将认证信息存到 session 等。
4、最终认证成功后的相关回调方法,主要将当前的认证信息放到 SecurityContextHolder 中并调用成功处理器做相应的 *** 作。
1、父类的 authResult = attemptAuthentication(request, response); 触发了自类的方法。
2、此方法首先判断请求方式是不是POST提交,必须是POST
3、从请求中获取 username 和 password ,并做一些处理
4、封装 Authenticaiton 类的实现类 UsernamePasswordAuthenticationToken
5、调用 AuthenticationManager 的 authenticate 方法进行验证
1、怎么触发的?
2、 ProviderManagerauthenticate(Authentication authentication);
3、此方法遍历所有的Providers,然后依次执行验证方法看是否支持 UsernamepasswordAuthenticationToken
4、若有一个能够支持当前token,则直接交由此 provider 处理并break。
5、若没一个 provider 验证成功,则交由父类来尝试处理
1、怎么触发的?
2、 DaoAuthenticationProvider
3、继承了 AbstractUserDetailsAuthenticationProvider
4、 AbstractUserDetailsAuthenticationProviderauthenticate() 首先调用了 user = thisretrieveUser(username, (UsernamePasswordAuthenticationToken)authentication);
5、调用我们自己的业务处理类
比如:
6、调用完 retrieveUser 方法继续回到抽象类的 authenticate 方法
7、首先做一些检查
8、调用 createSuccessAuthentication 方法进行授权成功
9、回到起点
进行session存储和成功后的处理器的调用等
只是简单说下类之间的调用顺序。
大功告成!
只需要一个html,一段配置,一个Service自己的业务类即可。
疑问:
1、接口login在哪定义的?
2、用户名 username 和密码 password 在哪接收的?
3、没有控制器怎么进入我们的 MyUserDetailsService 的方法?
解答:
1、 SpringSecurity 内置的,并且只能为 POST
2、名称不能变,必须是 username 和 password
3、自己看我上面的源码分析
在调用资源服务器的过程中,我们会将申请的token 作为header值进行传递,携带调用者的身份信息。但是资源服务器是如何通过token对调用者的身份进行判断的呢?
Security中有一个Filter实现了对token信息的转换,将token值转换成了调用者的用户信息。该filter就是 Oauth2AuthenticationProcessingFilter
一、查看源码
查看Oauth2AuthenticationProcessingFilter的doFilter方法
通过查看Oauth2AuthenticationProcessingFilter的dofilter方法,重点有两点
(1)将request中的token提取出来封装成Authentication对象
(2)将Authentication交给authenticationManager进行鉴权处理
下面我们重点看下这两处的处理。
二、token到Authentication对象转换实现
Authentication authentication = tokenExtractor extract(request);
tokenExtractor在Oauth2AuthencationProcessingFilter中的默认实现是BearerTokenExtractor,我们查看BearerTokenExtractor的extract()方法。
三、Authentication对象的鉴权
Authentication authResult = authenticationManager authenticate(authentication);
此处的authenticationManager的实现类是Oauth2AuthenticationManager,而不是我们之前一直提到的ProvicerManager。我们看下Oauth2AuthenticationManager中的authenticate()方法。
RemoteTokenService 的 loadAuthentication() 方法
用户认证转换类
接口层注入的 OAuth2Authentication对象中的 principal属性即在该类的extractAuthentication() 方法中实现的。
security默认使用的是 DefaultAccessTokenConverter类中的extractAuthentication()方法中使用。
通过继承UserAuthenticationConverter该类,实现其中的extractAuthentication()方法来满足我们自己构造 principal属性的需求。
在ResourceConfig类中,继续使用DefaultAccessTokenConverter,但是类中的UserAuthenticationConverter我们里换成我们自己的CustomUserAuthenticationConverter实现类。
我们构造的principal属性是map类,里面包含phone和userId两个字段。
spring对请求的处理过程如下:而security所有认证逻辑作为特殊的一个Filter加入到spring处理servelet的过滤链中,即FilterChainProxy;
而这个FilterChainProxy内部又有多个过滤器链FilterChain,每个链有matcher,用于匹配请求,请求来时选择最先匹配的一条过滤器链做权限认证,每条过滤器链又由多个多滤器Filter依序连接而成。如下图:
configuator配置类装配到builder类中,builder类借助confuguator类构造filter或者filterChain
SpringSecurity有两个重要的builder:
首先生成FilterChainProxy实例,将FilterChainProxy实例再封装到DelegatingFilterProxy(java web的标准过滤器),作为一个web的Filter再注册到spring上下文。
至于thiswebSecuritybuild()内部怎么实现的,后面再讲。
将FilterChainProxy再封装到DelegatingFilterProxy,在注入到spring上下文。有两种方式,如下:
上面讲到了通过调用thiswebSecuritybuild()方法产生FilterChainProxy实例,现在仔细分析具体怎么实现的。
由上可见,主要是init、configure、performBuild三个方法
21 init(WebSecurity)
会遍历所有之前加载好的配置类configuator(adaptor),调用其init。
其中配置类的init方法,主要是构造了>
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)