• spring security 4 filter 顺序及作用(转)


    spring security 4 filter 顺序及作用

    Spring Security 有两个作用:认证和授权

    一、Srping security 4 filter 别名及顺序

    spring security 4 标准filter别名和顺序,因为经常要用就保存到自己博客吧  点击访问官网链接

    Table 6.1. Standard Filter Aliases and Ordering

    AliasFilter ClassNamespace Element or Attribute

    CHANNEL_FILTER

    ChannelProcessingFilter

    http/intercept-url@requires-channel

    SECURITY_CONTEXT_FILTER

    SecurityContextPersistenceFilter

    http

    CONCURRENT_SESSION_FILTER

    ConcurrentSessionFilter

    session-management/concurrency-control

    HEADERS_FILTER

    HeaderWriterFilter

    http/headers

    CSRF_FILTER

    CsrfFilter

    http/csrf

    LOGOUT_FILTER

    LogoutFilter

    http/logout

    X509_FILTER

    X509AuthenticationFilter

    http/x509

    PRE_AUTH_FILTER

    AbstractPreAuthenticatedProcessingFilterSubclasses

    N/A

    CAS_FILTER

    CasAuthenticationFilter

    N/A

    FORM_LOGIN_FILTER

    UsernamePasswordAuthenticationFilter

    http/form-login

    BASIC_AUTH_FILTER

    BasicAuthenticationFilter

    http/http-basic

    SERVLET_API_SUPPORT_FILTER

    SecurityContextHolderAwareRequestFilter

    http/@servlet-api-provision

    JAAS_API_SUPPORT_FILTER

    JaasApiIntegrationFilter

    http/@jaas-api-provision

    REMEMBER_ME_FILTER

    RememberMeAuthenticationFilter

    http/remember-me

    ANONYMOUS_FILTER

    AnonymousAuthenticationFilter

    http/anonymous

    SESSION_MANAGEMENT_FILTER

    SessionManagementFilter

    session-management

    EXCEPTION_TRANSLATION_FILTER

    ExceptionTranslationFilter

    http

    FILTER_SECURITY_INTERCEPTOR

    FilterSecurityInterceptor

    http

    SWITCH_USER_FILTER

    SwitchUserFilter

    N/A

     

     

     

     

     

     

    二、Spring security filter作用

    2.1 默认filter链

    在程序启动时会打印出如下日志,该日志打印出了默认的filter链和顺序,其中SecurityContextPersistenceFilter为第一个filter,FilterSecurityInterceptor为最后一个filter。

    复制代码
    2018-02-11 15:24:17,204  INFO DefaultSecurityFilterChain - Creating filter chain: 
    org.springframework.security.web.util.matcher.AnyRequestMatcher@1, 
    [org.springframework.security.web.context.SecurityContextPersistenceFilter@3cf3957d, 
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@7ff34bd, 
    org.springframework.security.web.header.HeaderWriterFilter@4dad11a2, 
    org.springframework.security.web.authentication.logout.LogoutFilter@5be6ee89, 
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@5426eed3, 
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5da2a66c, 
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@23169e35, 
    org.springframework.security.web.session.SessionManagementFilter@5b1627ea, 
    org.springframework.security.web.access.ExceptionTranslationFilter@70b913f5, 
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor@2dfe7327]
    复制代码

    2.2 默认filter链作用

    默认有10条过滤链,下面逐个看下去。

    2.2.1 /index.html at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'

    SecurityContextPersistenceFilter 两个主要职责:

    a.请求到来时,通过HttpSessionSecurityContextRepository接口从Session中读取SecurityContext,如果读取结果为null,则创建之。

    复制代码
     1 public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
     2         HttpServletRequest request = requestResponseHolder.getRequest();
     3         HttpServletResponse response = requestResponseHolder.getResponse();
     4         HttpSession httpSession = request.getSession(false);
     5         // 从session中获取SecurityContext
     6         SecurityContext context = readSecurityContextFromSession(httpSession);
     7 
     8         if (context == null) {
     9             if (logger.isDebugEnabled()) {
    10                 logger.debug("No SecurityContext was available from the HttpSession: "
    11                         + httpSession + ". " + "A new one will be created.");
    12             }
    13             // 未读取到SecurityContext则新建一个SecurityContext
    14             context = generateNewContext();
    15 
    16         }
    17 
    18         SaveToSessionResponseWrapper wrappedResponse = new SaveToSessionResponseWrapper(
    19                 response, request, httpSession != null, context);
    20         requestResponseHolder.setResponse(wrappedResponse);
    21 
    22         if (isServlet3) {
    23             requestResponseHolder.setRequest(new Servlet3SaveToSessionRequestWrapper(
    24                     request, wrappedResponse));
    25         }
    26 
    27         return context;
    28     }
    复制代码

    获得SecurityContext之后,会将其存入SecurityContextHolder,其中SecurityContextHolder默认是ThreadLocalSecurityContextHolderStrategy实例

    复制代码
     1 private static void initialize() {
     2         if ((strategyName == null) || "".equals(strategyName)) {
     3             // Set default
     4             strategyName = MODE_THREADLOCAL;
     5         }
     6 
     7         if (strategyName.equals(MODE_THREADLOCAL)) {
     8             strategy = new ThreadLocalSecurityContextHolderStrategy();
     9         }
    10         // 以下内容省略
    11     }
    复制代码

    ThreadLocalSecurityContextHolderStrategy中的ContextHolder定义如下,注意这是一个ThreadLocal变量,线程局部变量。

    1 private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<SecurityContext>();

    b.请求结束时清空SecurityContextHolder,并将SecurityContext保存到Session中。

    复制代码
     1 finally {
     2             SecurityContext contextAfterChainExecution = SecurityContextHolder
     3                     .getContext();
     4             // Crucial removal of SecurityContextHolder contents - do this before anything
     5             // else.
     6             SecurityContextHolder.clearContext();
     7             repo.saveContext(contextAfterChainExecution, holder.getRequest(),
     8                     holder.getResponse());
     9             request.removeAttribute(FILTER_APPLIED);
    10 
    11             if (debug) {
    12                 logger.debug("SecurityContextHolder now cleared, as request processing completed");
    13             }
    14         }
    复制代码

    2.2.2 /index.html at position 2 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'

    提供了对securityContext和WebAsyncManager的集成,其会把SecurityContext设置到异步线程中,使其也能获取到用户上下文认证信息。

    复制代码
     1 @Override
     2     protected void doFilterInternal(HttpServletRequest request,
     3             HttpServletResponse response, FilterChain filterChain)
     4             throws ServletException, IOException {
     5         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
     6 
     7         SecurityContextCallableProcessingInterceptor securityProcessingInterceptor = (SecurityContextCallableProcessingInterceptor) asyncManager
     8                 .getCallableInterceptor(CALLABLE_INTERCEPTOR_KEY);
     9         if (securityProcessingInterceptor == null) {
    10             asyncManager.registerCallableInterceptor(CALLABLE_INTERCEPTOR_KEY,
    11                     new SecurityContextCallableProcessingInterceptor());
    12         }
    13 
    14         filterChain.doFilter(request, response);
    15     }
    复制代码

    2.2.3 /index.html at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter'

    用来给http response添加一些Header,比如X-Frame-Options、X-XSS-Protection*、X-Content-Type-Options。

    复制代码
     1 protected void doFilterInternal(HttpServletRequest request,
     2             HttpServletResponse response, FilterChain filterChain)
     3                     throws ServletException, IOException {
     4 
     5         HeaderWriterResponse headerWriterResponse = new HeaderWriterResponse(request,
     6                 response, this.headerWriters);
     7         try {
     8             filterChain.doFilter(request, headerWriterResponse);
     9         }
    10         finally {
    11                         // 向response header中添加header
    12             headerWriterResponse.writeHeaders();
    13         }
    14     }
    复制代码

    2.2.4 /index.html at position 4 of 10 in additional filter chain; firing Filter: 'LogoutFilter'

    处理退出登录的Filter,如果请求的url为/logout则会执行退出登录操作。

    复制代码
     1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
     2             throws IOException, ServletException {
     3         HttpServletRequest request = (HttpServletRequest) req;
     4         HttpServletResponse response = (HttpServletResponse) res;
     5         // 判断是否需要logout,判断request url是否匹配/logout
     6         if (requiresLogout(request, response)) {
     7             Authentication auth = SecurityContextHolder.getContext().getAuthentication();
     8 
     9             if (logger.isDebugEnabled()) {
    10                 logger.debug("Logging out user '" + auth
    11                         + "' and transferring to logout destination");
    12             }
    13             // 执行一系列的退出登录操作
    14             for (LogoutHandler handler : handlers) {
    15                 handler.logout(request, response, auth);
    16             }
    17             // 退出成功,执行logoutSuccessHandler进行重定向等操作
    18             logoutSuccessHandler.onLogoutSuccess(request, response, auth);
    19 
    20             return;
    21         }
    22 
    23         chain.doFilter(request, response);
    24     }
    复制代码

    2.2.5 /index.html at position 5 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'

    表单认证是最常用的一个认证方式,一个最直观的业务场景便是允许用户在表单中输入用户名和密码进行登录,而这背后的UsernamePasswordAuthenticationFilter,在整个Spring Security的认证体系中则扮演着至关重要的角色。

    UsernamePasswordAuthenticationFilter是继承自AbstractAuthenticationProcessingFilter。

    复制代码
     1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
     2             throws IOException, ServletException {
     3 
     4         HttpServletRequest request = (HttpServletRequest) req;
     5         HttpServletResponse response = (HttpServletResponse) res;
     6         // 判断是否需要执行登录认证,判断request url 是否能匹配/login
     7         if (!requiresAuthentication(request, response)) {
     8             chain.doFilter(request, response);
     9 
    10             return;
    11         }
    12 
    13         if (logger.isDebugEnabled()) {
    14             logger.debug("Request is to process authentication");
    15         }
    16 
    17         Authentication authResult;
    18 
    19         try {
    20             // UsernamePasswordAuthenticationFilter 实现该方法
    21             authResult = attemptAuthentication(request, response);
    22             if (authResult == null) {
    23                 // 子类未完成认证,立即返回
    24                 return;
    25             }
    26             sessionStrategy.onAuthentication(authResult, request, response);
    27         }
    28         // 在认证过程中抛出异常
    29         catch (InternalAuthenticationServiceException failed) {
    30             logger.error(
    31                     "An internal error occurred while trying to authenticate the user.",
    32                     failed);
    33             unsuccessfulAuthentication(request, response, failed);
    34 
    35             return;
    36         }
    37         catch (AuthenticationException failed) {
    38             // Authentication failed
    39             unsuccessfulAuthentication(request, response, failed);
    40 
    41             return;
    42         }
    43 
    44         // Authentication success
    45         if (continueChainBeforeSuccessfulAuthentication) {
    46             chain.doFilter(request, response);
    47         }
    48 
    49         successfulAuthentication(request, response, chain, authResult);
    50     }
    复制代码

    在UsernamePasswordAuthenticationFilter中实现了类attemptAuthentication,不过该类只实现了一个非常简化的版本,如果真的需要通过表单登录,是需要自己继承UsernamePasswordAuthenticationFilter并重载attemptAuthentication方法的。

    在AbstractAuthenticationProcessingFilter的doFilter方法中一开始是判断是否有必要进入到认证filter,这个过程其实是判断request url是否匹配/login,当然也可以通过filterProcessesUrl属性去配置匹配所使用的pattern。

    2.2.6 /index.html at position 6 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'

    将request存到session中,用于缓存request请求,可以用于恢复被登录而打断的请求

    复制代码
    1 public void doFilter(ServletRequest request, ServletResponse response,
    2             FilterChain chain) throws IOException, ServletException {
    3         // 从session中获取与当前request匹配的缓存request,并将缓存request从session删除
    4         HttpServletRequest wrappedSavedRequest = requestCache.getMatchingRequest(
    5                 (HttpServletRequest) request, (HttpServletResponse) response);
    6         // 如果requestCache中缓存了request,则使用缓存的request
    7         chain.doFilter(wrappedSavedRequest == null ? request : wrappedSavedRequest,
    8                 response);
    9     }
    复制代码

    此处从session中取出request,存储request是在ExceptionTranslationFilter中。具体可以参考探究 Spring Security 缓存请求

    2.2.7 /index.html at position 7 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'

    此过滤器对ServletRequest进行了一次包装,使得request具有更加丰富的API

    1     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
    2             throws IOException, ServletException {
    3         chain.doFilter(this.requestFactory.create((HttpServletRequest) req,
    4                 (HttpServletResponse) res), res);
    5     }

    2.2.8 /index.html at position 8 of 10 in additional filter chain; firing Filter: 'SessionManagementFilter'

    和session相关的过滤器,内部维护了一个SessionAuthenticationStrategy,两者组合使用,常用来防止session-fixation protection attack,以及限制同一用户开启多个会话的数量

    与登录认证拦截时作用一样,持久化用户登录信息,可以保存到session中,也可以保存到cookie或者redis中。

    复制代码
     1     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
     2             throws IOException, ServletException {
     3         HttpServletRequest request = (HttpServletRequest) req;
     4         HttpServletResponse response = (HttpServletResponse) res;
     5 
     6         if (request.getAttribute(FILTER_APPLIED) != null) {
     7             chain.doFilter(request, response);
     8             return;
     9         }
    10 
    11         request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
    12 
    13         if (!securityContextRepository.containsContext(request)) {
    14             Authentication authentication = SecurityContextHolder.getContext()
    15                     .getAuthentication();
    16 
    17             if (authentication != null && !trustResolver.isAnonymous(authentication)) {
    18                 // The user has been authenticated during the current request, so call the
    19                 // session strategy
    20                 try {
    21                     sessionAuthenticationStrategy.onAuthentication(authentication,
    22                             request, response);
    23                 }
    24                 catch (SessionAuthenticationException e) {
    25                     // The session strategy can reject the authentication
    26                     logger.debug(
    27                             "SessionAuthenticationStrategy rejected the authentication object",
    28                             e);
    29                     SecurityContextHolder.clearContext();
    30                     failureHandler.onAuthenticationFailure(request, response, e);
    31 
    32                     return;
    33                 }
    34                 // Eagerly save the security context to make it available for any possible
    35                 // re-entrant
    36                 // requests which may occur before the current request completes.
    37                 // SEC-1396.
    38                 securityContextRepository.saveContext(SecurityContextHolder.getContext(),
    39                         request, response);
    40             }
    41             else {
    42                 // No security context or authentication present. Check for a session
    43                 // timeout
    44                 if (request.getRequestedSessionId() != null
    45                         && !request.isRequestedSessionIdValid()) {
    46                     if (logger.isDebugEnabled()) {
    47                         logger.debug("Requested session ID "
    48                                 + request.getRequestedSessionId() + " is invalid.");
    49                     }
    50 
    51                     if (invalidSessionStrategy != null) {
    52                         invalidSessionStrategy
    53                                 .onInvalidSessionDetected(request, response);
    54                         return;
    55                     }
    56                 }
    57             }
    58         }
    59 
    60         chain.doFilter(request, response);
    61     }
    复制代码

    2.2.9 /index.html at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'

    异常拦截,其处在Filter链后部分,只能拦截其后面的节点并且只处理AuthenticationException与AccessDeniedException两个异常。

    AuthenticationException指的是未登录状态下访问受保护资源,AccessDeniedException指的是登陆了但是由于权限不足(比如普通用户访问管理员界面)。 

    复制代码
     1     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
     2             throws IOException, ServletException {
     3         HttpServletRequest request = (HttpServletRequest) req;
     4         HttpServletResponse response = (HttpServletResponse) res;
     5 
     6         try {
     7             // 直接执行后面的filter,并捕获异常
     8             chain.doFilter(request, response);
     9 
    10             logger.debug("Chain processed normally");
    11         }
    12         catch (IOException ex) {
    13             throw ex;
    14         }
    15         catch (Exception ex) {
    16             // 从异常堆栈中提取SpringSecurityException
    17             Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
    18             RuntimeException ase = (AuthenticationException) throwableAnalyzer
    19                     .getFirstThrowableOfType(AuthenticationException.class, causeChain);
    20 
    21             if (ase == null) {
    22                 ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(
    23                         AccessDeniedException.class, causeChain);
    24             }
    25 
    26             if (ase != null) {
    27                 // 处理异常
    28                 handleSpringSecurityException(request, response, chain, ase);
    29             }
    30             else {
    31                 // Rethrow ServletExceptions and RuntimeExceptions as-is
    32                 if (ex instanceof ServletException) {
    33                     throw (ServletException) ex;
    34                 }
    35                 else if (ex instanceof RuntimeException) {
    36                     throw (RuntimeException) ex;
    37                 }
    38 
    39                 // Wrap other Exceptions. This shouldn't actually happen
    40                 // as we've already covered all the possibilities for doFilter
    41                 throw new RuntimeException(ex);
    42             }
    43         }
    44     }
    复制代码

    在这个catch代码中通过从异常堆栈中捕获到Throwable[],然后通过handleSpringSecurityException方法处理异常,在该方法中只会去处理AuthenticationException和AccessDeniedException异常。

    复制代码
     1     private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, RuntimeException exception) throws IOException, ServletException {
     2     
     3         if (exception instanceof AuthenticationException) {
     4             // 认证异常,由sendStartAuthentication方法发起认证过程
     5             logger.debug("Authentication exception occurred; redirecting to authentication entry point", exception);
     6             sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
     7         } else if (exception instanceof AccessDeniedException) {
     8             // 访问权限异常
     9             if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
    10                 logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point", exception);
    11                 // 匿名用户重定向到认证入口点执行认证过程
    12                 sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException("Full authentication is required to access this resource"));
    13             } else {
    14                 // 拒绝访问,由accessDeniedHandler处理,response 403
    15                 logger.debug("Access is denied (user is not anonymous); delegating to AccessDeniedHandler", exception);
    16                 accessDeniedHandler.handle(request, response, (AccessDeniedException) exception);
    17             }
    18         }
    19     }
    20 
    21     protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, AuthenticationException reason) throws ServletException, IOException {
    22         // SEC-112: Clear the SecurityContextHolder's Authentication, as the existing Authentication is no longer considered valid
    23         // 将SecurityContext中的Authentication置为null
    24         SecurityContextHolder.getContext().setAuthentication(null);
    25         // 在调用认证前先将request保存到session
    26         requestCache.saveRequest(request, response);
    27         logger.debug("Calling Authentication entry point.");
    28         // 重定向到认证入口点执行认证
    29         authenticationEntryPoint.commence(request, response, reason);
    30     }
    复制代码

    2.2.10 /index.html at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'

     这个filter用于授权验证。FilterSecurityInterceptor的工作流程引用一下,可以理解如下:FilterSecurityInterceptor从SecurityContextHolder中获取Authentication对象,然后比对用户拥有的权限和资源所需的权限。前者可以通过Authentication对象直接获得,而后者则需要引入我们之前一直未提到过的两个类:SecurityMetadataSource,AccessDecisionManager。

    复制代码
      1     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      2         FilterInvocation fi = new FilterInvocation(request, response, chain);
      3         invoke(fi);
      4     }
      5     
      6     
      7     public void invoke(FilterInvocation fi) throws IOException, ServletException {
      8         if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null) && observeOncePerRequest) {
      9             // filter already applied to this request and user wants us to observe
     10             // once-per-request handling, so don't re-do security checking
     11             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
     12         } else {
     13             // first time this request being called, so perform security checking
     14             if (fi.getRequest() != null) {
     15                 fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
     16             }
     17 
     18             InterceptorStatusToken token = super.beforeInvocation(fi);
     19 
     20             try {
     21                 // 如果后面还有filter则继续执行
     22                 fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
     23             }
     24             finally {
     25                 // 保存securityContext
     26                 super.finallyInvocation(token);
     27             }
     28 
     29             super.afterInvocation(token, null);
     30         }
     31     }
     32     
     33     protected InterceptorStatusToken beforeInvocation(Object object) {
     34         Assert.notNull(object, "Object was null");
     35         final boolean debug = logger.isDebugEnabled();
     36 
     37         if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {
     38             throw new IllegalArgumentException(
     39                     "Security invocation attempted for object "
     40                             + object.getClass().getName()
     41                             + " but AbstractSecurityInterceptor only configured to support secure objects of type: "
     42                             + getSecureObjectClass());
     43         }
     44 
     45         // 获取配置的权限属性
     46         Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
     47 
     48         if (attributes == null || attributes.isEmpty()) {
     49             if (rejectPublicInvocations) {
     50                 throw new IllegalArgumentException(
     51                         "Secure object invocation "
     52                                 + object
     53                                 + " was denied as public invocations are not allowed via this interceptor. "
     54                                 + "This indicates a configuration error because the "
     55                                 + "rejectPublicInvocations property is set to 'true'");
     56             }
     57 
     58             if (debug) {
     59                 logger.debug("Public object - authentication not attempted");
     60             }
     61 
     62             publishEvent(new PublicInvocationEvent(object));
     63 
     64             return null; // no further work post-invocation
     65         }
     66 
     67         if (debug) {
     68             logger.debug("Secure object: " + object + "; Attributes: " + attributes);
     69         }
     70 
     71         if (SecurityContextHolder.getContext().getAuthentication() == null) {
     72             credentialsNotFound(messages.getMessage(
     73                     "AbstractSecurityInterceptor.authenticationNotFound",
     74                     "An Authentication object was not found in the SecurityContext"),
     75                     object, attributes);
     76         }
     77 
     78         // 获取Authentication,如果没有进行认证则认证后返回authentication
     79         Authentication authenticated = authenticateIfRequired();
     80 
     81         // Attempt authorization
     82         try {
     83             // 使用voter决策是否拥有资源需要的权限
     84             this.accessDecisionManager.decide(authenticated, object, attributes);
     85         } catch (AccessDeniedException accessDeniedException) {
     86             // 捕获到异常继续上抛
     87             publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, accessDeniedException));
     88             throw accessDeniedException;
     89         }
     90 
     91         if (debug) {
     92             logger.debug("Authorization successful");
     93         }
     94 
     95         if (publishAuthorizationSuccess) {
     96             publishEvent(new AuthorizedEvent(object, attributes, authenticated));
     97         }
     98 
     99         // Attempt to run as a different user
    100         Authentication runAs = this.runAsManager.buildRunAs(authenticated, object,
    101                 attributes);
    102 
    103         if (runAs == null) {
    104             if (debug) {
    105                 logger.debug("RunAsManager did not change Authentication object");
    106             }
    107 
    108             // no further work post-invocation
    109             return new InterceptorStatusToken(SecurityContextHolder.getContext(), false,
    110                     attributes, object);
    111         }
    112         else {
    113             if (debug) {
    114                 logger.debug("Switching to RunAs Authentication: " + runAs);
    115             }
    116 
    117             SecurityContext origCtx = SecurityContextHolder.getContext();
    118             SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
    119             SecurityContextHolder.getContext().setAuthentication(runAs);
    120 
    121             // need to revert to token.Authenticated post-invocation
    122             return new InterceptorStatusToken(origCtx, true, attributes, object);
    123         }
    124     }
    复制代码

    参考文章:

    https://blog.coding.net/blog/Explore-the-cache-request-of-Security-Spring

    http://blog.didispace.com/xjf-spring-security-4/

    http://blog.csdn.net/benjamin_whx/article/details/39204679

  • 相关阅读:
    ssize_t与size_t的前世今生
    jQuery 中的事件参数传递机制
    链表的container_of 疑惑
    c 语言使用疑惑小记
    IQueryFilter的WhereClause详解
    给自己鼓励...
    什么是闭包,我的理解
    WCF 第五章 行为 为服务终结点行为实现一个消息检测器
    WCF 第五章 行为 事务之事务服务行为
    WCF 第四章 绑定 wsHttpBinding
  • 原文地址:https://www.cnblogs.com/yasepix/p/14185298.html
Copyright © 2020-2023  润新知