Spring Security Ajax 登录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4912485/
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
Spring Security Ajax login
提问by MushMushon
I have implemented this security proccess in my project: Spring Security 3 - MVC Integration Tutorial (Part 2).
我已经在我的项目中实现了这个安全过程: Spring Security 3 - MVC 集成教程(第 2 部分)。
My problem is that I need to turn it into an Ajax-based login.
What do I need to do in order to make this XML suitable with just returning string/JSON to the client?
I understand that the problem might be in the form-logintag.
我的问题是我需要将其转换为基于 Ajax 的登录。我需要做什么才能使这个 XML 适合只向客户端返回字符串/JSON?我知道问题可能出在form-login标签上。
<?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: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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!-- This is where we configure Spring-Security -->
<http auto-config="true" use-expressions="true" access-denied-page="/Management/auth/denied" >
<intercept-url pattern="/Management/auth/login" access="permitAll"/>
<intercept-url pattern="/Management/main/admin" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/Management/main/common" access="hasRole('ROLE_USER')"/>
<form-login
login-page="/Management/auth/login"
authentication-failure-url="/Management/auth/login?error=true"
default-target-url="/Management/main/common"/>
<logout
invalidate-session="true"
logout-success-url="/Management/auth/login"
logout-url="/Management/auth/logout"/>
</http>
<!-- Declare an authentication-manager to use a custom userDetailsService -->
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
<!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
<beans:bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
<!-- A custom service where Spring will retrieve users and their corresponding access levels -->
<beans:bean id="customUserDetailsService" class="com.affiliates.service.CustomUserDetailsService"/>
</beans:beans>
回答by SergeyB
This is an old post, but it still comes up as one of the top results for "spring security ajax login," so I figured I'd share my solution. It follows Spring Security standards and is pretty simple to setup, the trick is to have 2 <http>elements in your security configuration, one for REST/Ajax and one for the rest of the app (regular HTML pages). The order in which <http>'s appear is important, it has to go from more specific to more generic URLs, just like <url-intercept>elements inside of a <http>.
这是一篇旧帖子,但它仍然是“spring security ajax login”的最佳结果之一,所以我想我会分享我的解决方案。它遵循 Spring Security 标准并且设置非常简单,诀窍是<http>在您的安全配置中有 2 个元素,一个用于 REST/Ajax,一个用于应用程序的其余部分(常规 HTML 页面)。<http>的出现顺序很重要,它必须从更具体的 URL 变为更通用的 URL,就像 a 中的<url-intercept>元素一样<http>。
Step 1: Setup Two Separate <http>'s
第 1 步:设置两个单独的<http>'s
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:beans="http://www.springframework.org/schema/beans"
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">
<!-- a shared request cache is required for multiple http elements -->
<beans:bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache" />
<!-- remove security from static resources to avoid going through the security filter chain -->
<http pattern="/resources/**" security="none" />
<!-- http config for REST services (AJAX interface)
=================================================== -->
<http auto-config="true" use-expressions="true" pattern="/rest/**">
<!-- login configuration
login-processing-url="/rest/security/login-processing" front-end AJAX requests for authentication POST to this URL
login-page="/rest/security/login-page" means "authentication is required"
authentication-failure-url="/rest/security/authentication-failure" means "authentication failed, bad credentials or other security exception"
default-target-url="/rest/security/default-target" front-end AJAX requests are redirected here after success authentication
-->
<form-login
login-processing-url="/rest/security/login-processing"
login-page="/rest/security/login-page"
authentication-failure-url="/rest/security/authentication-failure"
default-target-url="/rest/security/default-target"
always-use-default-target="true" />
<logout logout-url="/rest/security/logout-url" />
<!-- REST services can be secured here, will respond with JSON instead of HTML -->
<intercept-url pattern="/rest/calendar/**" access="hasRole('ROLE_USER')" />
<!-- other REST intercept-urls go here -->
<!-- end it with a catch all -->
<intercept-url pattern="/rest/**" access="isAuthenticated()" />
<!-- reference to the shared request cache -->
<request-cache ref="requestCache"/>
</http>
<!-- http config for regular HTML pages
=================================================== -->
<http auto-config="true" use-expressions="true">
<form-login
login-processing-url="/security/j_spring_security_check"
login-page="/login"
authentication-failure-url="/login?login_error=t" />
<logout logout-url="/security/j_spring_security_logout" />
<intercept-url pattern="/calendar/**" access="hasRole('ROLE_USER')" />
<!-- other intercept-urls go here -->
<!-- in my app's case, the HTML config ends with permitting all users and requiring HTTPS
it is always a good idea to send sensitive information like passwords over HTTPS -->
<intercept-url pattern="/**" access="permitAll" requires-channel="https" />
<!-- reference to the shared request cache -->
<request-cache ref="requestCache"/>
</http>
<!-- authentication manager and other configuration go below -->
</beans:beans>
Step 2: REST Authentication Controller
第 2 步:REST 身份验证控制器
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import flexjson.JSONSerializer;
@Controller
@RequestMapping(value = "/rest/security")
public class RestAuthenticationController {
public HttpHeaders getJsonHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
return headers;
}
@RequestMapping(value="/login-page", method = RequestMethod.GET)
public ResponseEntity<String> apiLoginPage() {
return new ResponseEntity<String>(getJsonHeaders(), HttpStatus.UNAUTHORIZED);
}
@RequestMapping(value="/authentication-failure", method = RequestMethod.GET)
public ResponseEntity<String> apiAuthenticationFailure() {
// return HttpStatus.OK to let your front-end know the request completed (no 401, it will cause you to go back to login again, loops, not good)
// include some message code to indicate unsuccessful login
return new ResponseEntity<String>("{\"success\" : false, \"message\" : \"authentication-failure\"}", getJsonHeaders(), HttpStatus.OK);
}
@RequestMapping(value="/default-target", method = RequestMethod.GET)
public ResponseEntity<String> apiDefaultTarget() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// exclude/include whatever fields you need
String userJson = new JSONSerializer().exclude("*.class", "*.password").serialize(authentication);
return new ResponseEntity<String>(userJson, getJsonHeaders(), HttpStatus.OK);
}
}
Step 3: Submit AJAX form and process the response, required jQuery's ajaxForm library
第三步:提交AJAX表单并处理响应,需要jQuery的ajaxForm库
<form action="/rest/security/login-processing" method="POST">
...
</form>
$('form').ajaxForm({
success: function(response, statusText, xhr, $form) {
console.log(response);
if(response == null || response.username == null) {
alert("authentication failure");
} else {
// response is JSON version of the Spring's Authentication
alert("authentication success");
}
},
error: function(response, statusText, error, $form) {
if(response != null && response.message == "authentication-failure") {
alert("authentication failure");
}
}
});
回答by martin
It depends on the implementation of your ajax-login. In any case, I guess you need to implement a custom filter. There are two good tutorials for using Spring Security with ExtJs:
这取决于您的 ajax-login 的实现。无论如何,我想您需要实现自定义过滤器。有两个很好的教程可以将 Spring Security 与 ExtJs 结合使用:
Integrating Spring Security 3 with Extjs
将 Spring Security 3 与 Extjs 集成
Integrating Spring Security with ExtJS Login Page
将 Spring Security 与 ExtJS 登录页面集成
It should work very similar for other Ajax login-forms.
它应该与其他 Ajax 登录表单非常相似。
回答by SergeyB
Spring is shifting away from XML based configurations and towards Java @Configurationclasses. Below is @Configurationversion of the setup explained in the post above (Spring Security Ajax login). Steps 2 & 3 remain the same, replace Step 1 with this code. The order is once again important, more specific definitions needs to be loaded before more generic ones, use @Order(1)and @Order(2)to control that.
Spring 正在从基于 XML 的配置转向 Java@Configuration类。下面是@Configuration上面帖子中解释的设置版本(Spring Security Ajax 登录)。步骤 2 和 3 保持不变,用此代码替换步骤 1。顺序再次很重要,需要在更通用的定义之前加载更具体的定义,使用@Order(1)和@Order(2)控制它。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
@Configuration
@EnableWebSecurity
public class WebMvcSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean(name = "requestCache")
public RequestCache getRequestCache() {
return new HttpSessionRequestCache();
}
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired private RequestCache requestCache;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.regexMatcher("/rest.*")
.authorizeRequests()
.antMatchers("/rest/calendar/**")
.hasAuthority("ROLE_USER")
.antMatchers("/rest/**")
.permitAll()
.and()
.headers()
.xssProtection()
.and()
.logout()
.logoutUrl("/rest/security/logout-url")
.and()
.requestCache()
.requestCache(requestCache)
.and()
.formLogin()
.loginProcessingUrl("/rest/security/login-processing")
.loginPage("/rest/security/login-page")
.failureUrl("/rest/security/authentication-failure")
.defaultSuccessUrl("/rest/security/default-target", false)
.and()
.httpBasic();
}
}
@Configuration
@Order(2)
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Autowired private RequestCache requestCache;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.regexMatchers("/calendar/.*")
.hasAuthority("ROLE_USER")
.regexMatchers("/.*")
.permitAll()
.and()
.logout()
.logoutUrl("/security/j_spring_security_logout")
.and()
.requestCache()
.requestCache(requestCache)
.and()
.formLogin()
.loginProcessingUrl("/security/j_spring_security_check")
.loginPage("/login")
.failureUrl("/login?login_error=t" )
.and()
.httpBasic();
}
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**")
.antMatchers("/sitemap.xml");
}
}
回答by user7688427
You can use HttpServletRequest.login(username,password)to login, just like:
您可以使用HttpServletRequest.login(username,password)登录,就像:
@Controller
@RequestMapping("/login")
public class AjaxLoginController {
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public String performLogin(
@RequestParam("username") String username,
@RequestParam("password") String password,
HttpServletRequest request, HttpServletResponse response) {
try {
request.login(username,password);
return "{\"status\": true}";
} catch (Exception e) {
return "{\"status\": false, \"error\": \"Bad Credentials\"}";
}
}

