重要的组件:Authentication(包含principal,authorities),Authority(角色),AuthenticationManager(认证管理),
AuthenticationProvider,ProviderManager,UserDetailsService,
UserDetails,User,AccessDecisionManager(权限管理),AffirmativeBased,AccessDecisionVoter,
SessionRegistry(实现类SessionRegistryImpl,维护SessionInfomation的注册,sessionInfomation包含Date lastRequest,principalsessionId,
expired),SessionAuthenticationStrategy(典型实用:确定session是否已存在,session固定攻击.
ConcurrentSessionControlAuthenticatioStrateg用于并发session登录处理策略)
spring security 默认filter(11个,顺序SecurityContextPersistenceFilter,ConcurrentSessionFilter,WebAsyncManagerIntegrationFilter,
HeaderWriterFilter,LogoutFilter,UsernamePasswordAuthenticationFilter,BasicAuthenticationFilter,RequestCacheAwareFilter,
SecurityContextHolderAwareRequestFilter,AnonymousAuthenticationFilter,SessionManagementFilter,ExceptionTranslationFilter,
FilterSecurityInterceptor).
spring security使用时,web.xml中声明DelegatingFilterProxy(shiro在新版本中 也是用该方法),filter-name 为springSecurityFilterChain,
真正的filter是FilterChainProxy,FilterChainProxy执行真正的过滤工作,FilterChainProxy 包含ListfilterChains,
如果在security的配置文件中每配置一个security:http 就会实例化一个SecurityFilterChain,SecurityFilterChain接口声明了
matchers(HttpServletRequest request)和ListgetFilters()方法,匹配url和获取filter,如果FilterChainProxy使用spring security
默认的话,FilterChainProxy默认包含十多个filterspring security 主要的filter(绝大本分extends GenericFilterBean)
1 SecurityContextPersisteneceFilter
首先要了解SecurityContext(如果了解过shiro的话,和shiro的Subject类似,使用了ThreadLocal模式),实现类SecurityContextImpl,
包含Authentication和AuthoritiesSecurityContextHolder持有securityContext(不过,filter全部执行完后,securityContext会从Thread中清除掉,
shiro的subject并不会,所以在filterChain执行完成后无法再获取securityContext,不过securityContext会设置到session中key为
SPRING_SECURITY_CONTEXT),securityContext的authentication会在AbstractAuthenticationProcessingFilter调用attempAuthentication,继而调用
providerManager的authenticate,如果用户认证成功则返回一个携带principal和authority的authentication设置到securityContext中,认证失败则为
null
2 ConcurrentSessionFilter
主要作用1.刷新session的最后请求时间 2.从SessionRegistry中获取SessionInformation,check session是否过期,如果expired,调用LogoutFilter
处理,典型的invalidate session,SessionInformationExpiredStrategy处理对应的request(比如:SimpleRedirectSessionInformationExpiredStrategy
重定向处理),同时发布HttpSessionDestroydEvent事件(如果在web.xml注册HttpSessionEventPublisher)
3. UsernamePasswordAuthenticationFilter
登陆认证,会调用AuthenticationManager.authenticatte->providerManager.authenticate->AuthenticateProvider.authenticate
以jdbc的认证形式执行过程:AbstractUserDetailsAuthenticationProvider.authenticate->DaoAuthenticationProvider.retrieveUser
(包含PasswordEncoder)->UserDetailsService.loadUserByUsername,UserDetailsService默认的实现类JdbcDaoImpl,CahingUserDetailsService,
UserDetailsManager接口用于user的维护(增删改),JdbcDaoImpl.loadUserByUsername从数据库中查询用户信息和用户的角色权限,获取User后,
AbstractUserDetailsAuthenticationProvider.authenticate()方法中继续执行preAuthenticationChecks.check(user)检测用户状态等,
additionalAuthenticationChecks执行密码校验
4. FilterSecurityInterceptor
doFilter方法中执行invoke(FilterInvocation fi),invoke方法包括super.beforeInvocation(fi),super.finallyInvocation(token),
super.afterInvocation(token, null),三个主要方法,super.beforeInvocation方法 校验当前authentication是否已认证,没有会继续调用
AuthenticationManager去authenticate,如果authentication已认证通过继续调用AccessDecisionManager.decide 查看用户是否有权限访问url,
finallyInvocation设置SecurityContext到SecurityContextHolder中,afterInvocation方法 没仔细看
5 ExceptionTranslationFilter
拦截FilterSecurityInterceptor 抛出的异常并处理AccessDeniedException和AuthenticationException(比如重定向到指定url)
6 SessionManagementFilter
当SecurityCOntextRepository.containsContext(request)为true是,该filter不会做任何处理,false时,查看当前SecurityContextHolder中
的authentication是否为空以及authentication是否为匿名用户,如果满足条件(不满足条件InvalidSessionStrategy也会做相应的处理),
SessionAuthenticationStrategy.onAuthentication,这个默认的实现类时CompositeSessionAuthenticationStrategy
(包含ListdelegateStrategies)做相应的处理,其中一个CuonCurrentSessionControlAuthenticationStrategy
做并发session处理的,如果onAuthentication失败,相应的AuthenticationFailureHandler会做处理(比如重定向到指定url),
spring security session维护
shiro中session的维护是有sessiongManager维护的,spring security是有SessionRegistry,默认的实现类SessionRegistryImpl,session的信息
保存在MapsessionIds中,SessiongInformation,包含Date lastRequest,Object principal,String sessionId,
boolean expired
AccessDecisionManager
访问决策管理,也就是是否有权限访问资源,spring security是 基于role 验证权限粒度多大(不如shiro,所以个人觉得在控制访问权限时,
可以直接在配置文件中按照模块配置你所需要的角色权限,基于url的设置,shiro可以在controller配置具体的操作权限,基于方法),采用vote形式,
在AffirmativeBased.decide中调用具体的AccessDesisionVoter.vote ,如果返回的反对deny>0就会抛出AccessDeniedException异常
spring security 也有注解,不过如果改配置设置到了application上下文的话,
无法对mvc上下文中管理的bean起到作用,比如controller
spring-security SecurityConfigurer, SecurityBuilder. SecurityConfigurer主要是来配置SecurityBuilder, SecurityBuilder 是用来构建相应的所需要的对象, 比如HttpSecurity用来 构建SecurityFilterChain, WebSecurity构建FilterChainProxy. AbstractConfiguredSecurityBuilder.doBuild()执行真正的build工作, doBuild方法内包含beforeInit() init() beforeConfigure() configure() performBuild(), beforeInit() 和 beforeConfigure() 用于扩展, init()和configure() 用于遍历执行AbstractConfiguredSecurityBuilder 中的所有SecurityConfigure的init和configure方法. SecurityConfigurer分为3个扩展SecurityConfigurerAdapter, WebSecurityConfigurer(WebSecurityConfigurerAdapter 配置WebSecurity和HttpSecurity), GlobalAuthenticationConfigurerAdapter. SecurityConfigurerAdapter 2个主要的继承类 UserDetailsAwareConfigurer, AbstractHttpConfigurer. UserDetailsAwareConfigurer用来配置AuthenticationManagerBuilder, AbstractHttpConfigurer大多都是配置HttpSecurity (一般都是构造相应的Filter添加到HttpSecurity中). 特殊的2个AbstractHttpConfigurer AbstractAuthenticationFilterConfigurer, AbstractInterceptUrlConfigurer. 第一个用来验证用户的,第二个用来验证用户是否有对应权限的.如FormLoginConfigurer()配置UsernamePasswordAuthenticationFilter. AbstractInterceptUrlConfigurer用来配置 FilterSecurityInterceptor.如ExpressionUrlAuthorizationConfigurer 通过内部ExpressionInterceptUrlRegistry REGISTRY将RequestMatcher, ConfigAttribute (如 hasAuthority("READ"), hasRole("ROLE_USER"), hasAnyRole('ROLE_USER', "RULE_ADMIN"), permitAll, denyAll) 转换成LinkedHashMap 设置到ExpressionBasedFilterInvocationSecurityMetadataSource 设置到FilterSecurityInterceptor中, 用于权限的校验,通过DefaultWebSecurityExpressionHandler来解析ConfigAttribute. WebSecurity -> FilterChainProxy HttpSecurity -> SecurityFilterChain User UserDetails UserDetailsService UserDetailsManager: UserDetailsService只定义了loadUserByUsername提供UserDetails服务接口, UserDetailsManager用于管理UserDetails包含了CUD相应的方法(没有查询方法, 定义在了UserDetailService中). 所以UserDetailsManager一般是通过继承UserDetailService而非使用组合的形式来使用UserDetailService的功能.User为UserDetails的默认实现类包含了用户的所有信息username, passwd, authority, accountNonExpired, accountNonLocked, credentialsNonExpired, enabled. AuthenticationManager(authenticate()返回Authentication) AuthenticationProvider(authenticate()返回Authentication) ProviderManager AuthenticationManagerBuilder.performBuild 返回的是ProviderManager(包含List),该类委托各个AuthenticationProvider去认证, 如果其中一个support 认证返回结果不为null也未抛出异常则认证通过. 目前给予用户名-密码模式的只有DaoAuthenticationProvider. 通过DaoAuthenticationProvider内部的UserDetailsService的不同, 获取 UserDetails的方式也不同, 比如给予内存使用的InMemoryUserDetailsManager, jdbc使用的JdbcUserDetailsManager(做个测试, 可以通过InMemoryUserDetailManagerConfigurer设置ObjectPostProcess来修改 InMemoryUserDetails获取userDetails的方式, 比如设置为JdbcDaoImpl). 如果想通过UserDetailsManager修改密码一般需要设置AuthenticationManager(需要校验username password是否正确) AccessDecisionManager访问控制权限 decide()方法无返回值, 通过抛出异常来确定是否有权限. HttpSecurity filter的order 定义在了FilterComparator中