Java Spring,Spring security:Spring security返回302,即使登录失败
我正在开发一个SpringMVC应用程序,其中我使用SpringSecurity进行身份验证和授权。我正在使用RestTemplate通过Android连接到webapp 目前,我遇到的问题是,即使登录失败,我也会收到302而不是200。因此,在客户端,我不知道登录失败了。之后,当用户尝试访问安全资源时,访问被拒绝,应用程序死亡 有人能告诉我当登录失败时如何返回正确的响应代码,以及如何通过响应代码检测它吗。非常感谢 securityApplicationContext.xml:Java Spring,Spring security:Spring security返回302,即使登录失败,java,spring,spring-mvc,spring-security,Java,Spring,Spring Mvc,Spring Security,我正在开发一个SpringMVC应用程序,其中我使用SpringSecurity进行身份验证和授权。我正在使用RestTemplate通过Android连接到webapp 目前,我遇到的问题是,即使登录失败,我也会收到302而不是200。因此,在客户端,我不知道登录失败了。之后,当用户尝试访问安全资源时,访问被拒绝,应用程序死亡 有人能告诉我当登录失败时如何返回正确的响应代码,以及如何通过响应代码检测它吗。非常感谢 securityApplicationContext.xml: <sec
<security:http pattern="/resources/template/demo/clients" security="none"/>
<security:http create-session="ifRequired" use-expressions="true" auto-config="false" disable-url-rewriting="true">
<security:form-login login-page="/login" username-parameter="j_username" password-parameter="j_password"
login-processing-url="/j_spring_security_check" default-target-url="/dashboard"
always-use-default-target="true" authentication-failure-url="/denied"/>
<security:remember-me key="_spring_security_remember_me" user-service-ref="userDetailsService"
token-validity-seconds="1209600" data-source-ref="dataSource"/>
<security:logout delete-cookies="JSESSIONID" invalidate-session="true" logout-url="/j_spring_security_logout"/>
<!--<security:intercept-url pattern="/**" requires-channel="https"/>-->
<security:port-mappings>
<security:port-mapping http="80" https="443"/>
</security:port-mappings>
<security:logout logout-url="/logout" logout-success-url="/" success-handler-ref="myLogoutHandler"/>
<security:session-management session-fixation-protection="migrateSession">
<security:concurrency-control session-registry-ref="sessionReg" max-sessions="5" expired-url="/sessionexpired"/>
</security:session-management>
</security:http>
<beans:bean id="sessionReg" class="org.springframework.security.core.session.SessionRegistryImpl"/>
<beans:bean id="rememberMeAuthenticationProvider"
class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg index="0" value="_spring_security_remember_me"/>
<beans:constructor-arg index="1" ref="userDetailsService"/>
<beans:constructor-arg index="2" ref="jdbcTokenRepository"/>
<property name="alwaysRemember" value="true"/>
</beans:bean>
<beans:bean id="jdbcTokenRepository"
class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
<beans:property name="createTableOnStartup" value="false"/>
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<!-- Remember me ends here -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="LoginServiceImpl">
<security:password-encoder ref="encoder"/>
</security:authentication-provider>
</security:authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11"/>
</beans:bean>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="LoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
</beans>
在Android方面,我是如何进行身份验证的:
private class LoginUserViaRest extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... params) {
final EditText userEmail = (EditText) findViewById(R.id.usernameText);
final EditText userPassword = (EditText) findViewById(R.id.PasswordField);
rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
StaticRestTemplate.jsessionid = rest.execute(StaticRestTemplate.baseURL+"j_spring_security_check", HttpMethod.POST,
new RequestCallback() {
@Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getBody().write(("j_username=" + userEmail.getText().toString() + "&j_password=" + userPassword.getText().toString()).getBytes());
}
}, new ResponseExtractor<String>() {
@Override
public String extractData(ClientHttpResponse response) throws IOException {
// Here I can get the code to determine if login was successful
List<String> cookies = response.getHeaders().get("Cookie");
if (cookies == null) {
cookies = response.getHeaders().get("Set-Cookie");
}
String cookie = cookies.get(cookies.size() - 1);
int start = cookie.indexOf('=');
int end = cookie.indexOf(';');
return cookie.substring(start + 1, end);
}
});
return null;
}
@Override
protected void onPostExecute(String aVoid) {
super.onPostExecute(aVoid);
}
}
私有类LoginUserSet扩展异步任务{
@凌驾
受保护字符串doInBackground(无效…参数){
最终EditText userEmail=(EditText)findViewById(R.id.usernameText);
最终的EditText用户密码=(EditText)findViewById(R.id.PasswordField);
添加(新的MappingJackson2HttpMessageConverter());
StaticRestTemplate.jsessionid=rest.execute(StaticRestTemplate.baseURL+“j_spring_security_check”,HttpMethod.POST,
新的RequestCallback(){
@凌驾
public void doWithRequest(ClientHttpRequest请求)引发IOException{
request.getBody().write(((“j_username=“+userEmail.getText().toString()+”&j_password=“+userPassword.getText().toString()).getBytes());
}
},新的响应抽取器(){
@凌驾
公共字符串提取数据(ClientHttpResponse响应)引发IOException{
//在这里,我可以获得确定登录是否成功的代码
List cookies=response.getHeaders().get(“Cookie”);
如果(cookies==null){
cookies=response.getHeaders().get(“设置Cookie”);
}
字符串cookie=cookies.get(cookies.size()-1);
int start=cookie.indexOf('=');
int end=cookie.indexOf(“;”);
返回cookie.substring(开始+1,结束);
}
});
返回null;
}
@凌驾
受保护的void onPostExecute(字符串避免){
super.onPostExecute(避免);
}
}
如果有任何进一步的解释,请让我知道。非常感谢。:-)
更新
Login.jsp:
<div class="col-xs-12 col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-4 col-lg-offset-4">
<div class="container-fluid white-div">
<div class="col-xs-12 col-md-12">
<h2><spring:message code="login.title"/></h2>
<form id="login-form" class="login-page" action="<c:url value='/j_spring_security_check'/>" method="POST">
<div class="form-group">
<label><spring:message code="login.label.email"/> <span id="eMailError" class="red-font"></span></label>
<div class="wrapper">
<input type="email" name="j_username" id="j_username" value="" class="form-control input" placeholder="<spring:message code="common.input.email.placeholder"/>">
<i class="fa fa-user"></i>
</div>
</div>
<div class="form-group">
<label><spring:message code="login.label.password"/> <span id="passwordError" class="red-font"></span></label>
<div class="wrapper">
<input type="password" name="j_password" id="j_password" class="form-control input" placeholder="<spring:message code="login.password.placeholder"/>">
<i class="fa fa-lock"></i>
</div>
</div>
<div class="checkbox">
<div class="col-xs-5">
<div class="row">
<label class="pull-left" for="show-password">
<input type="checkbox" id="show-password"><spring:message code="common.label.showpassword"/>
</label>
</div>
</div>
<a href="#" class="forgotpassword pull-right" data-toggle="modal" data-target="#passwordForgotModal"><spring:message code="login.forgotpassword"/></a>
</div>
<br>
<div class="form-group">
<button class="btn btn-primary btn-lg pull-right"><spring:message code="login.submit"/></button>
</div>
<div class="form-group">
<span><spring:message code="login.registration.text"/> <a href="/registration" class="forgotpassword"><spring:message code="login.registration.link"/></a></span>
</div>
</form>
</div>
</div>
<!-- <div class="g-signin2" data-onsuccess="onSignIn" data-theme="dark"></div> -->
<c:if test="${not empty url}">
<%-- <a href="${url}" class="btn btn-primary btn-lg btn-block si-facebook si-colored verticalAlignCenter"><spring:message code="common.facebook"/></a> --%>
</c:if>
</div>
</div>
安全性:表单登录是为web应用而不是REST客户端设计的。虽然你可以使用它,但你会遇到你在这里描述的那种麻烦
我建议改用security:httpbasic
(通过HTTPS进行安全保护)并每次发送登录详细信息
编辑:如果您坚持使用表单登录,您需要告诉restemplate
不要遵循重定向,这可以通过以下操作实现(使用Apache HttpComponents而不是标准的JREHttpUrlConnection
):
安全性:表单登录
是为web应用而不是REST客户端设计的。虽然你可以使用它,但你会遇到你在这里描述的那种麻烦
我建议改用security:httpbasic
(通过HTTPS进行安全保护)并每次发送登录详细信息
编辑:如果您坚持使用表单登录,您需要告诉restemplate
不要遵循重定向,这可以通过以下操作实现(使用Apache HttpComponents而不是标准的JREHttpUrlConnection
):
当然,您将得到一个302,因为这是登录过滤器所做的,它重定向到最初请求的URL。如果您不想这样做,请不要使用登录表单。@M.Deinum:Rest应该指向哪个URL?您必须为此创建一些内容。…@M.Deinum:Oh!!。你有任何链接有任何例子或类似的东西吗?我不知道从哪里开始。非常感谢。@M.Deinum:我有一个login.jsp,先生,我将用户名和密码传递给Spring security。你能帮助我理解如何将其与Spring Security集成吗。我正在更新我的主要帖子,包括它的内容。谢谢。当然你会得到一个302,因为登录过滤器就是这么做的,它会重定向到最初请求的URL。如果您不想这样做,请不要使用登录表单。@M.Deinum:那么我应该使用Rest指向哪个URL?您必须为此创建一些内容…@M.D
final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
final HttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(
new DefaultRedirectStrategy() {
@Override
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
return false;
}
}
).build();
factory.setHttpClient(httpClient);
restTemplate.setRequestFactory(factory);