我正在实施一个用于身份验证的登录页面。 AngularJS使用用户凭据向服务器发送发布请求。
//service.js
authApp.factory("loginFactory", function ($http) {
return{
login: function(username, password) {
var data = {username: username, password: password};
serialize = function(obj) {
var str = [];
for(var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
}
return $http({
method: 'POST',
url: 'http://localhost:8080/login',
data: serialize(data),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
});
}
}
});
我的控制器处理成功和失败。出于调试目的,我只打印出响应而不是重定向。
authApp.controller('LoginCtrl', ['$scope', '$location', 'loginFactory', function($scope, $location, loginFactory){
$scope.authenticate = function() {
loginFactory.login($scope.username, $scope.password)
.then(function(response) {
console.log(response);
}, function errorCallBack(response) {
console.log(response);
});
}
}]);
当我运行它时,POST请求将返回302而没有响应。并且GET请求将立即开始。如果密码正确,则会将其重定向到" http://localhost:8080/"。如果密码错误,它将被重定向到" http://localhost:8080/login?error。由于我没有任何一个路径的处理程序,它将返回401错误。 Angular控制器将捕获来自GET请求的响应,就好像它是来自Post请求的响应一样。
在后端,由Spring Security完成身份验证。这是安全配置:
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class)
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin();
//.loginPage("/login");
}
GET请求来自哪里?为什么原始帖子请求会触发重定向?
答案 0 :(得分:1)
GET请求是由于服务器返回302。在传统的登录形式中,spring将:
/
)('/ login?error`)浏览器透明地处理重定向。
如果您想更改spring的默认行为,我建议您参考tutorial。本教程使用基本身份验证而不是表单登录。但是,如果您需要表单登录,则必须实现自定义身份验证成功和失败处理程序。如下所示:
安全配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login","/error").permitAll()
.anyRequest()
.fullyAuthenticated().and().formLogin()
.failureHandler(customAuthenticationFailureHandler).and()
.logout().logoutSuccessHandler(ajaxLogoutSuccessHandler);
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(customAccessDeniedHandler);
}
CustomAuthenticationFailureHandler
返回状态代码401,而不是重定向到失败处理程序URL。
@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
AjaxLogoutSuccessHandler
返回状态200而不是重定向到注销成功网址
@Component
public class AjaxLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler
implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication)
throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_OK);
}
}
CustomAuthenticationEntryPoint
返回401而不是重定向到登录页面
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
CustomAccessDeniedHandler
返回401而不是重定向到访问被拒绝的页面。
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException,
ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
我希望这会有所帮助。