日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring security源码分析心得

發布時間:2025/4/5 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring security源码分析心得 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

看了半天的文檔及源碼,終于理出了spring-security的一些總體思路,spring security主要分認證(authentication)和授權(authority)。

1.認證authentication

認證主要代碼在spring-security-core下的包org.springframework.security.authentication下,主類:AuthenticationManager、AuthenticationProvider

其關系如下:

?

?2.授權Authorization

授權也稱Access Control,主要代碼在spring-security-core下的包org.springframework.security.access下,主類:AccessDecisionManager、SecurityMetadataSource。它們的關系通過ConfigAttribute關聯起來。

SecurityMetadataSource獲取ConfigAttribute,方法:

Collection<ConfigAttribute> getAttributes(Object object)throws IllegalArgumentException;

AccessDecisionManager根據進行授權,方法:

void decide(Authentication authentication, Object object,Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,InsufficientAuthenticationException;

其實現類:AffirmativeBased的授權邏輯如下:

/*** This concrete implementation simply polls all configured* {@link AccessDecisionVoter}s and grants access if any* <code>AccessDecisionVoter</code> voted affirmatively. Denies access only if there* was a deny vote AND no affirmative votes.* <p>* If every <code>AccessDecisionVoter</code> abstained from voting, the decision will* be based on the {@link #isAllowIfAllAbstainDecisions()} property (defaults to* false).* </p>** @param authentication the caller invoking the method* @param object the secured object* @param configAttributes the configuration attributes associated with the method* being invoked** @throws AccessDeniedException if access is denied*/public void decide(Authentication authentication, Object object,Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {int deny = 0;for (AccessDecisionVoter voter : getDecisionVoters()) {int result = voter.vote(authentication, object, configAttributes);if (logger.isDebugEnabled()) {logger.debug("Voter: " + voter + ", returned: " + result);}switch (result) {case AccessDecisionVoter.ACCESS_GRANTED:return;case AccessDecisionVoter.ACCESS_DENIED:deny++;break;default:break;}}if (deny > 0) {throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));}// To get this far, every AccessDecisionVoter abstained checkAllowIfAllAbstainDecisions();}

從上文可以看出,真正的授權是通過AccessDecisionVoter來完成的。

3.認證和授權的集成AbstractSecurityInterceptor

AbstractSecurityInterceptor包含了四個instance及其get/set方法

private AccessDecisionManager accessDecisionManager;private AfterInvocationManager afterInvocationManager;private AuthenticationManager authenticationManager = new NoOpAuthenticationManager();private RunAsManager runAsManager = new NullRunAsManager();

加一個抽象的方法:

/*** Indicates the type of secure objects the subclass will be presenting to the* abstract parent for processing. This is used to ensure collaborators wired to the* {@code AbstractSecurityInterceptor} all support the indicated secure object class.** @return the type of secure object the subclass provides services for*/public abstract Class<?> getSecureObjectClass();

AbstractSecurityInterceptor的實現類有兩個:

3.1?FilterSecurityInterceptor

定義:

/*** Performs security handling of HTTP resources via a filter implementation.* <p>* The <code>SecurityMetadataSource</code> required by this security interceptor is of* type {@link FilterInvocationSecurityMetadataSource}.* <p>* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.* </p>** @author Ben Alex* @author Rob Winch*/ public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {}

實現了標準的servlet的Filter接口,其邏輯如下:

/*** Method that is actually called by the filter chain. Simply delegates to the* {@link #invoke(FilterInvocation)} method.** @param request the servlet request* @param response the servlet response* @param chain the filter chain** @throws IOException if the filter chain fails* @throws ServletException if the filter chain fails*/public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {FilterInvocation fi = new FilterInvocation(request, response, chain);invoke(fi);}

最重要的實現invoke

public void invoke(FilterInvocation fi) throws IOException, ServletException {if ((fi.getRequest() != null)&& (fi.getRequest().getAttribute(FILTER_APPLIED) != null)&& observeOncePerRequest) {// filter already applied to this request and user wants us to observe// once-per-request handling, so don't re-do security checking fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}else {// first time this request being called, so perform security checkingif (fi.getRequest() != null) {fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);}InterceptorStatusToken token = super.beforeInvocation(fi);try {fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}finally {super.finallyInvocation(token);}super.afterInvocation(token, null);}}

3.2?MethodSecurityInterceptor

定義:

/*** Provides security interception of AOP Alliance based method invocations.* <p>* The <code>SecurityMetadataSource</code> required by this security interceptor is of* type {@link MethodSecurityMetadataSource}. This is shared with the AspectJ based* security interceptor (<code>AspectJSecurityInterceptor</code>), since both work with* Java <code>Method</code>s.* <p>* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.** @author Ben Alex* @author Rob Winch*/ public class MethodSecurityInterceptor extends AbstractSecurityInterceptor implementsMethodInterceptor {}

其invoke方法如下:

/*** This method should be used to enforce security on a <code>MethodInvocation</code>.** @param mi The method being invoked which requires a security decision** @return The returned value from the method invocation (possibly modified by the* {@code AfterInvocationManager}).** @throws Throwable if any error occurs*/public Object invoke(MethodInvocation mi) throws Throwable {InterceptorStatusToken token = super.beforeInvocation(mi);Object result;try {result = mi.proceed();}finally {super.finallyInvocation(token);}return super.afterInvocation(token, result);}

?4.Spring Security Java Config ---@EnableWebSecurity

?將@EnableWebSecurity注解加到@Configuration下來獲得spring securiy的安全性。

WebSecurityConfigurer定義的配置或者對WebSecurityConfigurerAdapter類的擴展類示例如下:

@Configuration@EnableWebSecuritypublic class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring()// Spring Security should completely ignore URLs starting with /resources/.antMatchers(&quot;/resources/&quot;);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers(&quot;/public/&quot;).permitAll().anyRequest().hasRole(&quot;USER&quot;).and()// Possibly more configuration ....formLogin() // enable form based log in// set permitAll for all URLs associated with Form Login .permitAll();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) {auth// enable in memory based authentication with a user named &quot;user&quot; and &quot;admin&quot;.inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;).and().withUser(&quot;admin&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;, &quot;ADMIN&quot;);}// Possibly more overridden methods ...}

4.1?WebSecurityConfigurer

?WebSecurityConfigurer允許對WebSecurity進行定制化,在絕大部分情景下,開發者使用@EnableWebSecurity注解或者對WebSecurityConfigurerAdapter進行重寫的方式來自動應用@EnableWebSecurity注解。定義如下:

public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extendsSecurityConfigurer<Filter, T> {}

4.2?WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapter提供了創建WebSecurityConfigurer實例的便利方法,它是一個基類。該類的實現通過重寫方法來實現定制化。

它自動從SpringFactoriesLoader查找AbstractHttpConfigurer,從而讓開發者可以擴展。為達到這個目的,必須創建一個AbstractHttpConfigurer的擴展類,然后在classpath路徑下創建一個文件META-INF/spring.factories,示例如下:

org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyClassThatExtendsAbstractHttpConfigurer

如果你有多個擴展類,可以使用逗號分隔,示例如下:

?org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyClassThatExtendsAbstractHttpConfigurer, sample.OtherThatExtendsAbstractHttpConfigurer

?4.2.1 初始化

?初始化分兩個過程:獲取HttpSecurity,配置FilterSecurityInterceptor到WebSecurity

public void init(final WebSecurity web) throws Exception {final HttpSecurity http = getHttp();web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {public void run() {FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);web.securityInterceptor(securityInterceptor);}});}

獲取HttpSecurity的過程:

/*** Creates the {@link HttpSecurity} or returns the current instance** ] * @return the {@link HttpSecurity}* @throws Exception*/@SuppressWarnings({ "rawtypes", "unchecked" })protected final HttpSecurity getHttp() throws Exception {if (http != null) {return http;}DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);AuthenticationManager authenticationManager = authenticationManager();authenticationBuilder.parentAuthenticationManager(authenticationManager);Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();http = new HttpSecurity(objectPostProcessor, authenticationBuilder,sharedObjects);if (!disableDefaults) {// @formatter:off http.csrf().and().addFilter(new WebAsyncManagerIntegrationFilter()).exceptionHandling().and().headers().and().sessionManagement().and().securityContext().and().requestCache().and().anonymous().and().servletApi().and().apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and().logout();// @formatter:onClassLoader classLoader = this.context.getClassLoader(); List<AbstractHttpConfigurer> defaultHttpConfigurers =SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);for(AbstractHttpConfigurer configurer : defaultHttpConfigurers) {http.apply(configurer);}}configure(http);return http;}

?5. xml配置解析類SecurityNamespaceHandler

它的解析器有以下幾種:

private void loadParsers() {// Parsersparsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());parsers.put(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());parsers.put(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());parsers.put(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());parsers.put(Elements.AUTHENTICATION_PROVIDER,new AuthenticationProviderBeanDefinitionParser());parsers.put(Elements.GLOBAL_METHOD_SECURITY,new GlobalMethodSecurityBeanDefinitionParser());parsers.put(Elements.AUTHENTICATION_MANAGER,new AuthenticationManagerBeanDefinitionParser());parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE,new MethodSecurityMetadataSourceBeanDefinitionParser());// Only load the web-namespace parsers if the web classes are availableif (ClassUtils.isPresent(FILTER_CHAIN_PROXY_CLASSNAME, getClass().getClassLoader())) {parsers.put(Elements.DEBUG, new DebugBeanDefinitionParser());parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE,new FilterInvocationSecurityMetadataSourceParser());parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();}if (ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {parsers.put(Elements.WEBSOCKET_MESSAGE_BROKER,new WebSocketMessageBrokerSecurityBeanDefinitionParser());}}

6.小結

spring支持注解和xml配置兩種方式,因此分析源碼可以從xml配置及注解兩方面入手,相互印證。

參考文獻:

【1】https://spring.io/guides/topicals/spring-security-architecture/

?【2】http://zzy.cincout.cn/2016/12/23/spring-security-2016-12-23-spring-security-01/

轉載于:https://www.cnblogs.com/davidwang456/p/6522925.html

總結

以上是生活随笔為你收集整理的spring security源码分析心得的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。