Spring Security4.1.3采用forward方式跳转登录界面,标签s:authorize不起作用问题

123 篇文章 0 订阅
27 篇文章 3 订阅
一、


      s:authorize定义:

<%@ taglib uri="http://www.springframework.org/security/tags" prefix="s"%>为security自定义标签

环境版本:security4.1.3


二、问题描述

标签使用:

<s:authorize access="hasAnyRole('USER','ADMIN')">
							<li><a href="<%=basePathHeader %>logout">退出 Logout </a></li>
							<li><a href="<%=basePathHeader %>xxxx" class="current">修改密码 Change Password</a></li>
						</s:authorize>

从没有访问权限页面forward方式跳转过来该标签不起作用,(redirect方式没问题)


三、问题定位

初步定位为跳转方式不同引起,看源码:

1.跳转的时候授权信息Authentication会被置空

SecurityContextImpl.setAuthentication(Authentication) line: 72	
ExceptionTranslationFilter.sendStartAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, AuthenticationException) line: 201	
ExceptionTranslationFilter.handleSpringSecurityException(HttpServletRequest, HttpServletResponse, FilterChain, RuntimeException) line: 178	
ExceptionTranslationFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 134	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
SessionManagementFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 137	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
AnonymousAuthenticationFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 111	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
SecurityContextHolderAwareRequestFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 169	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
RequestCacheAwareFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 63	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
BasicAuthenticationFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 158	
BasicAuthenticationFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
UsernamePasswordAuthenticationFilter(AbstractAuthenticationProcessingFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 200	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
LogoutFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 121	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
HeaderWriterFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 66	
HeaderWriterFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
WebAsyncManagerIntegrationFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 56	
WebAsyncManagerIntegrationFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
ConcurrentSessionFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 134	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
SecurityContextPersistenceFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 105	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
FilterChainProxy.doFilterInternal(ServletRequest, ServletResponse, FilterChain) line: 214	
FilterChainProxy.doFilter(ServletRequest, ServletResponse, FilterChain) line: 177	
DelegatingFilterProxy.invokeDelegate(Filter, ServletRequest, ServletResponse, FilterChain) line: 346	
DelegatingFilterProxy.doFilter(ServletRequest, ServletResponse, FilterChain) line: 262	
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
SiteMeshFilter(ContentBufferingFilter).bufferAndPostProcess(FilterChain, HttpServletRequest, HttpServletResponse, Selector) line: 169	
SiteMeshFilter(ContentBufferingFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 126	
SiteMeshFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 120	
ConfigurableSiteMeshFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 163	
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
CharacterEncodingFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 197	
CharacterEncodingFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107	
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
StandardWrapperValve.invoke(Request, Response) line: 222	
StandardContextValve.invoke(Request, Response) line: 123	
NonLoginAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 472	
StandardHostValve.invoke(Request, Response) line: 168	
ErrorReportValve.invoke(Request, Response) line: 99	
AccessLogValve.invoke(Request, Response) line: 929	
StandardEngineValve.invoke(Request, Response) line: 118	
CoyoteAdapter.service(Request, Response) line: 407	
Http11AprProcessor(AbstractHttp11Processor<S>).process(SocketWrapper<S>) line: 1002	
Http11AprProtocol$Http11ConnectionHandler(AbstractProtocol$AbstractConnectionHandler<S,P>).process(SocketWrapper<S>, SocketStatus) line: 585	
AprEndpoint$SocketProcessor.run() line: 1813	
ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 1145	
ThreadPoolExecutor$Worker.run() line: 615	
TaskThread(Thread).run() line: 745	


ExceptionTranslationFilter.java

protected void sendStartAuthentication(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain,
			AuthenticationException reason) throws ServletException, IOException {
		// SEC-112: Clear the SecurityContextHolder's Authentication, as the
		// existing Authentication is no longer considered valid
		SecurityContextHolder.getContext().setAuthentication(null);    //清空
		requestCache.saveRequest(request, response);
		logger.debug("Calling Authentication entry point.");
		authenticationEntryPoint.commence(request, response, reason);
	}


2. redirect方式会走过滤器AnonymousAuthenticationFilter,会创建Authentication,授权信息

SecurityContextImpl.setAuthentication(Authentication) line: 72	
AnonymousAuthenticationFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 96	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
SecurityContextHolderAwareRequestFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 169	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
RequestCacheAwareFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 63	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
BasicAuthenticationFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 158	
BasicAuthenticationFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
UsernamePasswordAuthenticationFilter(AbstractAuthenticationProcessingFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 200	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
LogoutFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 121	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
HeaderWriterFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 66	
HeaderWriterFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
WebAsyncManagerIntegrationFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 56	
WebAsyncManagerIntegrationFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
ConcurrentSessionFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 134	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
SecurityContextPersistenceFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 105	
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 331	
FilterChainProxy.doFilterInternal(ServletRequest, ServletResponse, FilterChain) line: 214	
FilterChainProxy.doFilter(ServletRequest, ServletResponse, FilterChain) line: 177	
DelegatingFilterProxy.invokeDelegate(Filter, ServletRequest, ServletResponse, FilterChain) line: 346	
DelegatingFilterProxy.doFilter(ServletRequest, ServletResponse, FilterChain) line: 262	
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
SiteMeshFilter(ContentBufferingFilter).bufferAndPostProcess(FilterChain, HttpServletRequest, HttpServletResponse, Selector) line: 169	
SiteMeshFilter(ContentBufferingFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 126	
SiteMeshFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 120	
ConfigurableSiteMeshFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 163	
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
CharacterEncodingFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 197	
CharacterEncodingFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107	
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243	
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210	
StandardWrapperValve.invoke(Request, Response) line: 222	
StandardContextValve.invoke(Request, Response) line: 123	
NonLoginAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 472	
StandardHostValve.invoke(Request, Response) line: 168	
ErrorReportValve.invoke(Request, Response) line: 99	
AccessLogValve.invoke(Request, Response) line: 929	
StandardEngineValve.invoke(Request, Response) line: 118	
CoyoteAdapter.service(Request, Response) line: 407	
Http11AprProcessor(AbstractHttp11Processor<S>).process(SocketWrapper<S>) line: 1002	
Http11AprProtocol$Http11ConnectionHandler(AbstractProtocol$AbstractConnectionHandler<S,P>).process(SocketWrapper<S>, SocketStatus) line: 585	
AprEndpoint$SocketProcessor.run() line: 1813	
ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 1145	
ThreadPoolExecutor$Worker.run() line: 615	
TaskThread(Thread).run() line: 745	

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {

		if (SecurityContextHolder.getContext().getAuthentication() == null) {
			SecurityContextHolder.getContext().setAuthentication(
					createAuthentication((HttpServletRequest) req));     //创建Authentication

			if (logger.isDebugEnabled()) {
				logger.debug("Populated SecurityContextHolder with anonymous token: '"
						+ SecurityContextHolder.getContext().getAuthentication() + "'");
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("SecurityContextHolder not populated with anonymous token, as it already contained: '"
						+ SecurityContextHolder.getContext().getAuthentication() + "'");
			}
		}

		chain.doFilter(req, res);
	}


protected Authentication createAuthentication(HttpServletRequest request) {
		AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key,
				principal, authorities);
		auth.setDetails(authenticationDetailsSource.buildDetails(request));

		return auth;
	}

3、forward方式不会走过滤器,不会再创建授权信息Authentication,因此为null

标签中源码,JspAuthorizeTag.java

public int doStartTag() throws JspException {
		try {
			authorized = super.authorize();

			if (!authorized && TagLibConfig.isUiSecurityDisabled()) {
				pageContext.getOut().write(TagLibConfig.getSecuredUiPrefix());
			}

			if (var != null) {
				pageContext.setAttribute(var, authorized, PageContext.PAGE_SCOPE);
			}

			return TagLibConfig.evalOrSkip(authorized);

		}
		catch (IOException e) {
			throw new JspException(e);
		}
	}


AbstractAuthorizeTag.java

public boolean authorize() throws IOException {
		boolean isAuthorized;

		if (StringUtils.hasText(getAccess())) {
			isAuthorized = authorizeUsingAccessExpression();

		}
		else if (StringUtils.hasText(getUrl())) {
			isAuthorized = authorizeUsingUrlCheck();

		}
		else {
			isAuthorized = false;

		}

		return isAuthorized;
	}



public boolean authorizeUsingAccessExpression() throws IOException {
  if (SecurityContextHolder.getContext().getAuthentication() == null) {                       //为null返回false,因此标签不起作用
   return false;
  }

  SecurityExpressionHandler<FilterInvocation> handler = getExpressionHandler();

  Expression accessExpression;
  try {
   accessExpression = handler.getExpressionParser().parseExpression(getAccess());

  }
  catch (ParseException e) {
   IOException ioException = new IOException();
   ioException.initCause(e);
   throw ioException;
  }

  return ExpressionUtils.evaluateAsBoolean(accessExpression,
    createExpressionEvaluationContext(handler));
 }



/**
	 * Returns EVAL_BODY_INCLUDE if the authorized flag is true or UI security has been
	 * disabled. Otherwise returns SKIP_BODY.
	 *
	 * @param authorized whether the user is authorized to see the content or not
	 */
	public static int evalOrSkip(boolean authorized) {
		if (authorized || DISABLE_UI_SECURITY) {
			return Tag.EVAL_BODY_INCLUDE;
		}

		return Tag.SKIP_BODY;         //跳过主题
	}


四、解决方式:

1.这种问题可以不用解决,没有什么影响

本身登录界面就没有什么授权信息


2.跳转到登录界面时可以模拟AnonymousAuthenticationFilter创建Authentication信息,这个解决方案还没实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值