authentication-manager>
authentication-provideruser-service-ref="userDetailsService"/>
authentication-manager>
首先定义了一个使用ApacheDerby数据库的数据源,SpringSecurity的org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl类使用该数据源来加载用户信息。
最后配置认证管理器使用该UserDetailsService。
3、publicinterfaceSecurityContext
extendsSerializable
Interfacedefiningtheminimumsecurityinformationassociatedwiththecurrentthreadofexecution.
ThesecuritycontextisstoredinaSecurityContextHolder.
org.springframework.security.core.context.SecurityContext接口表示的是当前应用的安全上下文。
通过此接口可以获取和设置当前的认证对象。
publicinterfaceAuthentication
extendsPrincipal,Serializable
Representsanauthenticationrequest.
AnAuthenticationobjectisnotconsideredauthenticateduntilitisprocessedbyanAuthenticationManager.
StoredinarequestSecurityContext.
org.springframework.security.core.Authentication接口用来表示认证对象。
通过认证对象的方法可以判断当前用户是否已经通过认证,以及获取当前认证用户的相关信息,包括用户名、密码和权限等。
要使用此认证对象,首先需要获取到SecurityContext对象。
通过org.springframework.security.core.context.SecurityContextHolder类提供的静态方法getContext()就可以获取。
再通过SecurityContext对象的getAuthentication()就可以得到认证对象。
通过认证对象的getPrincipal()方法就可以获得当前的认证主体,通常是UserDetails接口的实现。
处理过程:
典型的认证过程就是当用户输入了用户名和密码之后,UserDetailService通过用户名找到对应的UserDetails对象,接着比较密码是否匹配。
如果不匹配,则返回出错信息;如果匹配的话,说明用户认证成功,就创建一个Authentication的对象,如org.springframework.security.authentication.UsernamePasswordAuthenticationToken类的对象。
再通过SecurityContext的setAuthentication()方法来设置此认证对象。
publicclassFilterSecurityInterceptor
extendsAbstractSecurityInterceptor
implementsFilter,Ordered
PerformssecurityhandlingofHTTPresourcesviaafilterimplementation.
TheObjectDefinitionSourcerequiredbythissecurityinterceptorisoftypeFilterInvocationDefinitionSource.
RefertoAbstractSecurityInterceptorfordetailsontheworkflow.
通过实现Filter接口来完成对HTTP资源的安全控制。
FilterSecurityInterceptor要求有一个FilterInvocationDefinitionSource类型的ObjectDefinitonSource参数。
参考AbstractSecurityInterceptor获得更多的工作流程细节。
FilterSecurityInterceptor从名字来看好像是一个拦截器,但是从上面可以看出它实现了Filter接口。
所以这个伪Interceptor可以直接处理request请求,它里面有这样的方法:
doFilter
publicvoiddoFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throwsIOException,
ServletException
Methodthatisactuallycalledbythefilterchain.Simplydelegatestotheinvoke(FilterInvocation)method.
publicabstractclassAbstractSecurityInterceptor
extendsObject
implementsInitializingBean,ApplicationEventPublisherAware,MessageSourceAware
Abstractclassthatimplementssecurityinterceptionforsecureobjects.
TheAbstractSecurityInterceptorwillensuretheproperstartupconfigurationofthesecurityinterceptor.Itwillalsoimplementtheproperhandlingofsecureobjectinvocations,namely:
这一个实现对安全对象安全管理的抽象类。
AbstractSecurityInterceptor将会保证安全拦截的正确启动配置。
也会实现对安全对象调用的恰当管理,也就是:
1.ObtaintheAuthenticationobjectfromtheSecurityContextHolder.
从SecurityContextHolder中获得Authentication对象。
2.DetermineiftherequestrelatestoasecuredorpublicinvocationbylookingupthesecureobjectrequestagainsttheObjectDefinitionSource.
如果请求关系到一个安全的或者是公共的调用就通过去查找ObjectDefinitionSource确定是否一个安全的对象请求。
3.Foraninvocationthatissecured(thereisaConfigAttributeDefinitionforthesecureobjectinvocation):
a.IfeithertheAuthentication.isAuthenticated()returnsfalse,orthealwaysReauthenticateistrue,authenticatetherequestagainsttheconfiguredAuthenticationManager.Whenauthenticated,replacetheAuthenticationobjectontheSecurityContextHolderwiththereturnedvalue.
b.AuthorizetherequestagainsttheconfiguredAccessDecisionManager.
c.Performanyrun-asreplacementviatheconfiguredRunAsManager.
d.Passcontrolbacktotheconcretesubclass,whichwillactuallyproceedwithexecutingtheobject.AInterceptorStatusTokenisreturnedsothatafterthesubclasshasfinishedproceedingwithexecutionoftheobject,itsfinallyclausecanensuretheAbstractSecurityInterceptorisre-calledandtidiesupcorrectly.
e.Theconcretesubclasswillre-calltheAbstractSecurityInterceptorviatheafterInvocation(InterceptorStatusToken,Object)method.
f.IftheRunAsManagerreplacedtheAuthenticationobject,returntheSecurityContextHoldertotheobjectthatexistedafterthecalltoAuthenticationManager.
g.IfanAfterInvocationManagerisdefined,invoketheinvocationmanagerandallowittoreplacetheobjectduetobereturnedtothecaller.
4.Foraninvocationthatispublic(thereisnoConfigAttributeDefinitionforthesecureobjectinvocation):
a.Asdescribedabove,theconcretesubclasswillbereturnedanInterceptorStatusTokenwhichissubsequentlyre-presentedtotheAbstractSecurityInterceptorafterthesecureobjecthasbeenexecuted.TheAbstractSecurityInterceptorwilltakenofurtheractionwhenitsafterInvocation(InterceptorStatusToken,Object)iscalled.
5.Controlagainreturnstotheconcretesubclass,alongwiththeObjectthatshouldbereturnedtothecaller.Thesubclasswillthenreturnthatresultorexceptiontotheoriginalcaller.
publicinterfaceObjectDefinitionSource
ImplementedbyclassesthatstoreandcanidentifytheConfigAttributeDefinitionthatappliestoagivensecureobjectinvocation.
被这些可以存储和识别适用于给出的安全对象调用的ConfigAttributeDefinition类实现。
publicclassConfigAttributeDefinition
extendsObject
implementsSerializable
HoldsagroupofConfigAttributesthatareassociatedwithagivensecureobjecttarget-effectivelyaCollection.
Oncecreated,theobjectisimmutable.
AlltheConfigAttributeDefinitionsassociatedwithagivenAbstractSecurityInterceptorarestoredinanObjectDefinitionSource.
拥有一组与给出的安全目标对象关联的ConfigAttributes---事实上是一个集合。
也就是这个对象内容保存有装有配置属性的集合。
一旦被创建,这个对象就是不变的。
所有与AbstractSecurityInterceptor关联的ConfigAttributeDefinitons都存储在ObjectDefinitionSource中。
也就是操作ObjectDefinitionSource实际上是为了获取ConfigAttributeDefinitions。
FilterSecurityInterceptor该filter也是个重量级的filter,主要是个拦截器的作用。
该filter需要配置一下属性:
1、authenticationManager校验密码并获取角色信息
2、objectDefinitionSource
3、accessDecisionManager--àAffirmativeBased【具备两个属性:
allowIfAllAbstainDecisions,decisionVoters】而decisionVoters可以配置为:
a:
RoleVoter根据ROLE_来确定是否通过
b:
AuthenticatedVoter
FilterSecurityInterceptor.doFilter中做了什么呢?
首先将request,response,chain封装成FilterInvocationfi,然后执行一下:
a:
beforeInvocation
b:
fi.getChain().doFilter()
c:
afterInvocation
三个方法
A、beforeInvocation(FilterInvocation)方法返回值是InterceptorStatusToken,这个方法都做了什么呢?
以下说明了它的运行逻辑:
1、filterSecurityInterceptor中配置了objectDefinitionSource,调用其getAttributes(fi)方法,getAttribute(fi)方法中调用fi.getRequestUrl()得到URL,然后调用objectDefinitonSource.lookupAttribute(url)这个lookup方法就可以从数据库resource表中获取url对应的resource。
2、将1中查询出来的resource与url逐一比较,如果匹配,则获得相应GrantedAuthority[]即roles。
3、将2中GrantedAuthority[]逐一getAuthority后根据‘,’分隔拼凑成字符串authStr,并且newConfigAttributeEditor(),再调用ConfigAttributeEditor.setAsText(authStr)和ConfigAttributeEditor.getValue(),将value强制转化成ConfigAttributeDefinition返回。
setAsText方面里面:
newConfigAttributeDefinition,再将authStr拆分成数组,逐一调用addConfigAttribute方法将SecurityConfig(auth)add到ConfigAttributeDefiniton中,再setVlaue将ConfigAttributeDefinition设置为value。
因此调用getValue的返回值可以强制转化为ConfigAttributeDefinition类。
4、通过SecurityContextHolder.getContext().getAuthentication()获取Authentication。
此处根据配置及Authentication.isAuthenticated()判断可能会再次调用authenticationManager的authenticate方法。
5、调用accessDecisionManager.decide(authenticated,FilterInvocation,ConfigAttributeDefiniton),下面分析一下AffirmativeBased这个decisionManager是如何decide的?
1、对AffirmativeBased配置的每一个decisionVoter执行:
调用voter.vote(Authention,obj,ConfigAttributeDefiniton)获取是通过还是denny还是弃权。
2、如果denny的数量>0,则异常不通过,如果有一个通过则decide方法完成返回
3、如果AffirmativeBased有allowIfAllAbstainDecisions(“如果全部弃权则通过”)属性,如果false,则抛出异常
RoleVoter.vote方法:
从ConfigAttributeDefinition