springsecurity登录
首先
1.UsernamePasswordAuthenticationFilter->attemptAuthentication (AbstractAuthenticationProcessingFilter 父类 )
successfulAuthentication
1.1 ProviderManager-> authenticate
1.1.1 AbstractUserDetailsAuthenticationProvider -> authenticate
DaoAuthenticationProvider ->retrieveUser
UsernamePasswordAuthenticationFilter
Authentication
AuthenticationManager
AuthenticationProvider
UserDetailsService
// 回到起点进行后续操作,比如缓存认证信息到session和调用成功后的处理器等等
UsernamePasswordAuthenticationFilter
接口login在哪定义的?
public UsernamePasswordAuthenticationFilter() {
super(new AntPathRequestMatcher("/login", "POST"));
}
https://www.jianshu.com/p/a65f883de0c1
-- 第一天
认证总入口
AuthenticationManager --> ProviderManager 多种认证实现来进行认证,
依照次序去认证,认证成功则立即返回。
身份信息的存放容器SecurityContextHolder
身份信息的抽象Authentication,身份认证器AuthenticationManager及其认证流程
UsernamePasswordAuthenticationFilter->attemptAuthentication (AbstractAuthenticationProcessingFilter 父类 )
UsernamePasswordAuthenticationFilter 进行封装用户名密码 attemptAuthentication 方法
( 用户名 和 密码封装 UsernamePasswordAuthenticationToken)
AbstractUserDetailsAuthenticationProvider 方法:authenticate
是否正确? retrieveUser 方法
retrieveUser只有第一个参数起主要作用,返回一个UserDetails
然后将结果进行对比是否正常,操作方法:additionalAuthenticationChecks
(比对密码的过程,用到了PasswordEncoder和SaltSource,密码加密和盐的概念相信不用我赘述了,它们为保障安全而设计,都是比较基础的概念。)
iris 将返回的结果进行封装。里面包含了很多相关的其他信息数据 ,在 UserDetailServiceImpl中
UserDetails最详细的用户信息,这个接口涵盖了一些必要的用户信息字段,具体的实现类对它进行了扩展。
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
Authentication的getCredentials()与UserDetails中的getPassword()需要被区分对待,前者是用户提交的密码凭证,后者是用户正确的密码,认证器其实就是对这两者的比对。
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
除了“/”,”/home”(首页),”/login”(登录),”/logout”(注销),之外,其他路径都需要认证。
指定“/login”该路径为登录页面,当未认证的用户尝试访问任何受保护的资源时,都会跳转到“/login”。 没有权限。默认跳登陆
默认指定“/logout”为注销页面
-- 第二天
@EnableWebSecurity
WebSecurityConfiguration-->springSecurityFilterChain 注册了 。
只允许认证用户在同一时间只有一个实例是如何配置的。
session管理
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.permitAll()
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login?expired");
}
过滤器链(重要的)
1. SecurityContextPersistenceFilter 两个主要职责:请求来临时,创建SecurityContext安全上下文信息,请求结束时清空SecurityContextHolder。
2.UsernamePasswordAuthenticationFilter 这个会重点分析,表单提交了username和password,被封装成token进行一系列的认证,便是主要通过这个过滤器完成的,在表单认证的方法中,这是最最关键的过滤器。
3.AnonymousAuthenticationFilter 匿名身份过滤器,这个过滤器个人认为很重要,需要将它与UsernamePasswordAuthenticationFilter 放在一起比较理解,spring security为了兼容未登录的访问,也走了一套认证流程,只不过是一个匿名的身份。
4.ExceptionTranslationFilter 直译成异常翻译过滤器,还是比较形象的,这个过滤器本身不处理异常,而是将认证过程中出现的异常交给内部维护的一些类去处理
5.FilterSecurityInterceptor 这个过滤器决定了访问特定路径应该具备的权限,访问的用户的角色,权限是什么?访问的路径需要什么样的角色和权限?
有了认证,有了请求的封装,有了Session的关联…还缺一个:由什么控制哪些资源是受限的,这些受限的资源需要什么权限,需要什么角色…这一切和访问控制相关的操作,都是由FilterSecurityInterceptor完成的
6. token自定义:==> IpAuthenticationToken extends AbstractAuthenticationToken
oauth2
http://dev.auth.server/oauthserver/oauth/authorize?client_id=oauthclient-system&redirect_uri=http://dev.new.egrant.cn:8081/egrantweb/sp_sec_ck&response_type=code&state=wTOC9V
在请求到达/oauth/token之前经过了ClientCredentialsTokenEndpointFilter这个过滤器
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
...
String clientId = request.getParameter("client_id");
String clientSecret = request.getParameter("client_secret");
...
clientId = clientId.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(clientId,
clientSecret);
return this.getAuthenticationManager().authenticate(authRequest);
debug可以发现UserDetailsService的实现被适配成了ClientDetailsUserDetailsService,这个设计是将client客户端的信息(client_id,client_secret)适配成用户的信息(username,password),这样我们的认证流程就不需要修改了。
Token处理端点TokenEndpoint(掌握)
TokenGranter 来颁发token。其中OAuth2AccessToken的实现类DefaultOAuth2AccessToken就是最终在控制台得到的token序列化之前的原始类:
tokenGranter的设计思路是使用CompositeTokenGranter管理一个List列表,每一种grantType对应一个具体的真正授权者,在debug过程中可以发现CompositeTokenGranter 内部就是在循环调用五种TokenGranter实现类的grant方法,而granter内部则是通过grantType来区分是否是各自的授权类型。
ResourceOwnerPasswordTokenGranter ==> password密码模式
AuthorizationCodeTokenGranter ==> authorization_code授权码模式
ClientCredentialsTokenGranter ==> client_credentials客户端模式
ImplicitTokenGranter ==> implicit简化模式
RefreshTokenGranter ==>refresh_token 刷新token专用
http://localhost:8080/order/1?access_token=950a7cc9-5a8a-42c9-a693-40e817b1a4b0 访问
进入:
OAuth2AuthenticationProcessingFilter
OAuth2的身份管理器—OAuth2AuthenticationManager
AuthorizationServerTokenServices