使用 Spring 3 在 REST 中登录/注销
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14733418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Login/logout in REST with Spring 3
提问by FKhan
We are developing RESTful webservices with Spring 3 and we need to have the functionality of login/logout, something like /webservices/login/<username>/<password>/and /webservices/logout. The session should be stored in the context until the session is timed out or logged out to allow consumption of other webservices. Any request to access webservices without session information should be rejected. Looking for state-of-the-art solution for this scenario.
我们正在使用 Spring 3 开发 RESTful Web 服务,我们需要具有登录/注销功能,例如/webservices/login/<username>/<password>/和/webservices/logout。会话应存储在上下文中,直到会话超时或注销以允许使用其他 Web 服务。任何在没有会话信息的情况下访问网络服务的请求都应该被拒绝。正在为这种情况寻找最先进的解决方案。
I am actually resurrecting the question asked here Spring Security 3 programmatically login, which is still not properly answered. Please specify the changes needed in web.xml as well.
我实际上是在重新提出这里提出的问题Spring Security 3 以编程方式登录,但仍然没有正确回答。请同时在 web.xml 中指定所需的更改。
回答by rootkit
I would suggest defining your Spring Security filters completely manually. It's not that difficult, and you get full control over your login/logout behaviour.
我建议完全手动定义您的 Spring Security 过滤器。这并不难,您可以完全控制您的登录/注销行为。
First of all, you will need standard web.xml blurb to delegate filter chain handling to Spring (remove async-supported if you are not on Servlet API ver 3):
首先,您需要标准的 web.xml blurb 将过滤器链处理委派给 Spring(如果您不在 Servlet API 版本 3 上,请删除 async-supported):
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<async-supported>true</async-supported>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Now, in security context you will define filters separately for each path. Filters can authenticate user, log out user, check security credentials etc.
现在,在安全上下文中,您将为每个路径分别定义过滤器。过滤器可以验证用户、注销用户、检查安全凭证等。
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/login" filters="sif,wsFilter"/>
<sec:filter-chain pattern="/logout" filters="sif,logoutFilter" />
<sec:filter-chain pattern="/rest/**" filters="sif,fsi"/>
</sec:filter-chain-map>
</bean>
The XML above tells Spring to pass requests to specific context-relative URLs through filter chains. First thing in any of the filter chains is establishing security context - 'sif' bean takes care of that.
上面的 XML 告诉 Spring 通过过滤器链将请求传递给特定的上下文相关 URL。任何过滤器链中的第一件事都是建立安全上下文 - 'sif' bean 负责。
<bean id="sif" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
Next filter in chain can now either add data to the security context (read: log in/log out user), or make a decision as to whether allow access based on said security context.
链中的下一个过滤器现在可以将数据添加到安全上下文(读取:登录/注销用户),或者根据所述安全上下文决定是否允许访问。
For your login URL you will want a filter that reads authentication data from the request, validates it, and in turn stores it in security context (which is stored in session):
对于您的登录 URL,您需要一个过滤器,从请求中读取身份验证数据,对其进行验证,然后将其存储在安全上下文中(存储在会话中):
<bean id="wsFilter" class="my.own.security.AuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="myAuthSuccessHandler"/>
<property name="passwordParameter" value="pass"></property>
<property name="usernameParameter" value="user"></property>
<property name="postOnly" value="false"></property>
You can use Spring generic UsernamePasswordAuthenticationFilterbut the reason I use my own implementation is to continue filter chain processing (default implementation assumes user will get redirected on successful auth and terminates filter chain), and being able to process authentication every time username and password is passed to it:
您可以使用 Spring generic,UsernamePasswordAuthenticationFilter但我使用自己的实现的原因是继续过滤器链处理(默认实现假设用户将在成功的身份验证时重定向并终止过滤器链),并且能够在每次用户名和密码传递给时处理身份验证它:
public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return ( StringUtils.hasText(obtainUsername(request)) && StringUtils.hasText(obtainPassword(request)) );
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException{
super.successfulAuthentication(request, response, chain, authResult);
chain.doFilter(request, response);
}
You can add any number of your own filter implementations for /login path, such as authentication using HTTP basic auth header, digest header, or even extract username/pwd from the request body. Spring provides a bunch of filters for that.
您可以为 /login 路径添加任意数量的自己的过滤器实现,例如使用 HTTP 基本身份验证标头、摘要标头进行身份验证,甚至从请求正文中提取用户名/密码。Spring为此提供了一堆过滤器。
I have my own auth success handler who overrides the default redirect strategy:
我有自己的身份验证成功处理程序,可以覆盖默认重定向策略:
public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@PostConstruct
public void afterPropertiesSet() {
setRedirectStrategy(new NoRedirectStrategy());
}
protected class NoRedirectStrategy implements RedirectStrategy {
@Override
public void sendRedirect(HttpServletRequest request,
HttpServletResponse response, String url) throws IOException {
// no redirect
}
}
}
You don't have to have custom auth success handler (and probably custom auth filter as well) if you're ok with user being redirected after successful login (redirect URL can be customized, check docs)
如果您对成功登录后被重定向的用户感到满意(可以自定义重定向 URL,请查看文档),您就不必拥有自定义身份验证成功处理程序(也可能是自定义身份验证过滤器)
Define authentication manager who will be responsible for retrieving user's details:
定义负责检索用户详细信息的身份验证管理器:
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="myAuthAuthProvider"/>
</sec:authentication-manager>
<bean id="myAuthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="myUserDetailsImpl"/>
</bean>
</property>
</bean>
You will have to provide your own user details bean implementation here.
您必须在此处提供您自己的用户详细信息 bean 实现。
Logout filter: responsible for clearing security context
注销过滤器:负责清除安全上下文
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
Generic authentication stuff:
通用身份验证内容:
<bean id="httpRequestAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
</list>
</property>
</bean>
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>
<bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/>
Access control filter (should be self-explanatory):
访问控制过滤器(应该是不言自明的):
<bean id="fsi" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="myAuthenticationManager"/>
<property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
<property name="securityMetadataSource">
<sec:filter-invocation-definition-source>
<sec:intercept-url pattern="/rest/**" access="ROLE_REST"/>
</sec:filter-invocation-definition-source>
</property>
</bean>
You should also be able to secure your REST services with @Securedannotations on methods.
您还应该能够使用@Secured方法注释来保护您的 REST 服务。
Context above was plucked from existing REST service webapp - sorry for any possible typos.
上面的上下文是从现有的 REST 服务 webapp 中提取的 - 对于任何可能的错字,抱歉。
It is also possible to do at least most of what is implemented here by using stock secSpring tags, but I prefer custom approach as that gives me most control.
也可以通过使用股票secSpring 标签来至少完成这里实现的大部分内容,但我更喜欢自定义方法,因为这给了我最大的控制权。
Hope this at least gets you started.
希望这至少能让你开始。

