页面加载后正在清除Spring SecurityContext
我正在将ZK与Spring安全性集成,到目前为止,我已经配置了Spring安全性,因此除了登录页面之外,所有URL都是安全的。当通过导航到不同的URL进行页面切换时,这当然很好 但是,当我动态更改某些内容时,即通过更改ZK中包含元素的src属性,然后在该新内容的控制器内调用SecurityContextHolder.getContext.getAuthentication,我不会获得任何类型的凭据,但会获得一个空值作为身份验证对象。我的猜测是,罪魁祸首在调试中被这一行指出:页面加载后正在清除Spring SecurityContext,spring,spring-security,zk,Spring,Spring Security,Zk,我正在将ZK与Spring安全性集成,到目前为止,我已经配置了Spring安全性,因此除了登录页面之外,所有URL都是安全的。当通过导航到不同的URL进行页面切换时,这当然很好 但是,当我动态更改某些内容时,即通过更改ZK中包含元素的src属性,然后在该新内容的控制器内调用SecurityContextHolder.getContext.getAuthentication,我不会获得任何类型的凭据,但会获得一个空值作为身份验证对象。我的猜测是,罪魁祸首在调试中被这一行指出: SecurityCo
SecurityContextPersistenceFilter:97 - SecurityContextHolder now cleared, as request processing completed
问题是我从使用基本身份验证的REST Web服务获取所有数据,因此我需要获取每个请求的用户凭据,其中包括动态加载内容的凭据
我知道我可以将SecurityContext级别设置为全局级别,但我也了解到这是一种不好的做法,可能会导致用户获取其他人的凭据
PS:有趣的是,如果不是:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
我使用:
Authentication authentication = ((org.springframework.security.core.context.SecurityContextImpl)session().getAttribute("SPRING_SECURITY_CONTEXT")).getAuthentication();
我的身份验证对象实际上就在那里。所以这里一定有我遗漏的东西
编辑:这是我的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>XESAC</display-name>
<!-- Spring Security -->
<!-- A servlet filter capturing every user requests and sending them to
the configured security filters to make sure access is authorized. -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>sigur-ui.root</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring/appcontext-spring.xml,classpath:/spring/appcontext-security.xml</param-value>
</context-param>
<listener>
<description>Spring Loader</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<description>Used to cleanup when a session is destroyed</description>
<display-name>ZK Session Cleaner</display-name>
<listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<description>
The ZK loader for ZUML pages</description>
<servlet-name>zkLoader</servlet-name>
<servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
<init-param>
<param-name>update-uri</param-name>
<param-value>/zkau</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<description>The asynchronous update engine for ZK</description>
<servlet-name>auEngine</servlet-name>
<servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>auEngine</servlet-name>
<url-pattern>/zkau/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>dspLoader</servlet-name>
<servlet-class>org.zkoss.web.servlet.dsp.InterpreterServlet</servlet-class>
<init-param>
<param-name>class-resource</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dspLoader</servlet-name>
<url-pattern>*.dsp</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.zul</welcome-file>
</welcome-file-list>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.zul</location>
</error-page>
</web-app>
appcontext-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:zksp="http://www.zkoss.org/2008/zkspring/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<global-method-security secured-annotations="enabled" pre-post-annotations="disabled"/>
<http pattern="/resources/**" security="none" />
<http pattern="/zkau/**" security="none" />
<http auto-config="true" use-expressions="true">
<!-- En funcion del rol de cada usuario -->
<intercept-url pattern="/login.zul" access="permitAll" />
<intercept-url pattern="/timeout.zul" access="permitAll" />
<intercept-url pattern="/css/**" access="permitAll" />
<intercept-url pattern="/img/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<!-- Areas Patterns -->
<form-login login-page="/login.zul" authentication-failure-url="/login.zul?login_error=1" default-target-url="/index.zul" />
<logout logout-success-url="/login.zul" logout-url="/logout" invalidate-session="true" />
</http>
<!-- Autenticación mock para las pruebas -->
<authentication-manager erase-credentials="false">
<authentication-provider ref="myProvider" />
</authentication-manager>
<beans:bean id="myProvider" class="com.myapp.provider.MyProvider" />
</beans:beans>
MyProvider.java这是我自己的一个类,它针对REST端点进行身份验证:
public class MyProvider implements AuthenticationProvider {
@Autowired
private IAuthenticationService authenticationService;
@Autowired
private HttpSession session;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
UserDetailsDTO userDetails = authenticationService.doAuthenticate(authentication);
if (null != userDetails && !userDetails.isAnonymous()) {
session.setAttribute("user", userDetails);
List<GrantedAuthority> grantedAuths = new ArrayList<>();
//should set the roles here
return new UsernamePasswordAuthenticationToken(userDetails, password, grantedAuths);
}
else {
return null;
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
这种行为是绝对正确的。首先,REST要求是无状态的,所以每个请求都必须经过协商。如果您希望在人机界面上持久化,则必须执行以下操作:
<beans:bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />
但是说
<security:http pattern="/rest/**" create-session="stateless" />
这种行为是绝对正确的。首先,REST要求是无状态的,所以每个请求都必须经过协商。如果您希望在人机界面上持久化,则必须执行以下操作:
<beans:bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />
但是说
<security:http pattern="/rest/**" create-session="stateless" />
在安全配置中,您有以下行:
<http pattern="/zkau/**" security="none" />
所有以/zkau开头的URL都会完全绕过spring安全过滤器。如果ZK使用那些未经spring security处理的URL,则身份验证将为空
您至少应该从appcontext security.xml中删除该行,在您的安全配置中,您有该行:
<http pattern="/zkau/**" security="none" />
所有以/zkau开头的URL都会完全绕过spring安全过滤器。如果ZK使用那些未经spring security处理的URL,则身份验证将为空
您至少应该从appcontext security.xml中删除该行,这里涉及到两层,REST层和UI层。我的问题来自UI层,其中有一个用户会话,因为它是一个web应用程序。我没有在我的REST端点上保留状态,这就是为什么我需要为我发出的每个请求获取用户和密码,并将它们放在我正在使用的基本身份验证中的身份验证头中。你的陈述想说什么?尝试上面的代码片段。如果您的REST是一个调用UI的浏览器,那么可以将其保留下来,否则不建议这样做。此外,我将清空REST服务的两个端点。一个用于浏览器,一个用于真正的REST客户端。这应该能解决你的问题。但我不明白你的答案,你建议我把这些台词放在哪里?你能详细解释一下你的答案吗?我的问题是,在从UI对REST端点的不同调用之间,我丢失了UI层上的SecurityContext。我在REST层很好,或者至少我认为我很好,如果我不好,请纠正我,我捕获每个请求,然后通过基本身份验证获取每个请求的用户信息,并且它正在工作。谁在执行REST调用?服务器是否使用JSESSIONID响应,客户端是否提供了JSESSIONID?否;UI层正在进行这些调用。对于用户来说,无论是否调用REST端点都是透明的。不,我没有使用任何sessionId信息,因为我的REST是无状态的,我不应该依赖它,对吗?该过程如下:用户加载一个需要数据访问的页面,数据取决于用户,REST请求使用授权头加上用户+密码完成;REST设置为基本身份验证服务接收请求,根据数据库检查这些凭据,并允许在REST层上使用@PreAuthorize注释访问请求的方法Im。这里涉及两层,REST层和UI层。我的问题来自UI层,其中有一个用户会话,因为它是一个web应用程序。我没有在我的REST端点上保留状态,这就是为什么我需要为我发出的每个请求获取用户和密码,并将它们放在我正在使用的基本身份验证中的身份验证头中。你的陈述想说什么?尝试上面的代码片段。如果您的REST是一个调用UI的浏览器,那么可以将其保留下来,否则不建议这样做。此外,我将清空REST服务的两个端点。一个用于浏览器,一个用于真正的REST客户端。这应该能解决你的问题。但我不明白你的答案,你建议我把这些台词放在哪里?你能扩展一下吗
你的回答解释了原因吗?我的问题是,在从UI对REST端点的不同调用之间,我丢失了UI层上的SecurityContext。我在REST层很好,或者至少我认为我很好,如果我不好,请纠正我,我捕获每个请求,然后通过基本身份验证获取每个请求的用户信息,并且它正在工作。谁在执行REST调用?服务器是否使用JSESSIONID响应,客户端是否提供了JSESSIONID?否;UI层正在进行这些调用。对于用户来说,无论是否调用REST端点都是透明的。不,我没有使用任何sessionId信息,因为我的REST是无状态的,我不应该依赖它,对吗?该过程如下:用户加载一个需要数据访问的页面,数据取决于用户,REST请求使用授权头加上用户+密码完成;REST设置为基本身份验证服务接收请求,根据数据库检查这些凭据,并允许使用REST层上的@PreAuthorize注释访问请求的方法Im。我对ZK了解不多,但这一行在appcontext-security.xm中意味着什么?如果ZK使用这些URL,它们不会被spring安全性处理,身份验证将被null处理;这不知怎么地使它工作了,我从其他地方复制的那部分代码,你能告诉我URL模式是什么吗?很遗憾,这破坏了我的登录页面,我如何修复它?我对ZK不太了解,但这一行在你的appcontext-security.xm中意味着什么?如果ZK使用这些URL,它们不会被spring安全性处理,身份验证将被null处理;这不知怎么地使它工作了,我从别处复制的那部分代码,你能告诉我URL模式是什么吗?很遗憾,这破坏了我的登录页面,我如何修复它?