我们在前端使用AngularJS,在后端使用spring。 Spring安全性应该进行身份验证和登录,但它甚至不能在spring的教程(https://spring.io/guides/tutorials/spring-security-and-angular-js/)的帮助下工作。每当我们尝试登录" user" -service时,主体对象为空。在前端,我们收到了这个答案:data = Object {data: "", status: 200, config: Object, statusText: "OK"}
EVERYTIME。使用正确或不正确的数据登录并不重要......我阅读了很多文章,但我无法找到解决方案。
我们的 login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Login</title>
<link rel="stylesheet" type="text/css" href="stylesheets/bootstrap.min.css" />
<script src="scripts/angular.min.js"></script>
<script src="scripts/login.js"></script>
<style>
body {
position: relative;
}
</style>
</head>
<body ng-app="LoginApp">
<div class="modal show" ng-controller="LoginController">
<div class="modal-header">
<h1 class="text-center">Login</h1>
</div>
<div class="modal-body">
<form>
<div class="control-group">
<div class="controls">
<input class="input-block-level" type="text" placeholder="Username" ng-model="username" ng-change="checkValid()" ng-disabled="requesting">
</div>
</div>
<div class="control-group">
<div class="controls">
<input class="input-block-level" type="password" placeholder="Password" ng-model="password" ng-change="checkValid()" ng-disabled="requesting">
</div>
</div>
<span class="error" ng-bind="errormessage" ng-show="error"></span>
<!--
<div class="control-group">
<label class="checkbox">
<input type="checkbox">Remember me</label>
</div>
-->
</form>
</div>
<div class="modal-footer">
<!--
<button class="btn btn-link">Forgot password?</button>
-->
<button class="btn btnExtra btn-large btn-primary" ng-click="submitLogin()" ng-disabled="requesting || !valid">Login</button>
</div>
</div>
</body>
</html>
我们的 login.js :
(function(angular) {
const app = angular.module("LoginApp",[]);
app.controller("LoginController", ["$scope", "$http", function($scope, $http){
$scope.username = "";
$scope.password = "";
$scope.errormessage = "";
$scope.error = false;
$scope.valid = false;
$scope.requesting = false;
$scope.submitLogin = function() {
$scope.requesting = true;
$scope.error = false;
const credentials = {
username: $scope.username,
password: $scope.password
};
const headers = credentials ? {authorization : "Basic "
+ btoa(credentials.username + ":" + credentials.password)
} : {};
$http.get("user", { headers: headers }).then(function(data){
if(data.data.name) {
window.location.href = "/";
}
else {
$scope.error = true;
$scope.requesting = false;
$scope.errormessage = "Username / Passwort ist falsch!";
}
},
function(reason) {
$scope.error = true;
$scope.requesting = false;
if(reason.status === 404 || reason.status === 408){
$scope.errormessage = "Verbindung zum Server konnte nicht hergestellt werden!";
}else if (reason.status === 403){
$scope.errormessage = "Username / Passwort ist falsch!";
}else{
$scope.errormessage = "Unbekannter Fehler ist bei der Anfrage aufgetreten! Bitte versuchen Sie es erneut";
}
})
};
$scope.checkValid = function(){
if($scope.username != undefined && $scope.username != null && $scope.username.length > 1 &&
$scope.password != undefined && $scope.password != null && $scope.password.length > 1){
$scope.valid = true;
}else{
$scope.valid = false;
}
};
}
]);
})(window.angular);
我们的身份验证服务(如教程或许多帖子中所述):
@RestController
public class UserController {
@RequestMapping(value = "/user")
public Principal user(Principal user) {
return user;
}
}
带有自定义过滤器的SecurityWebAppInitializer,该过滤器应记录IP和用户名。
@Order(2)
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
@Override
protected void afterSpringSecurityFilterChain(ServletContext servletContext) {
super.beforeSpringSecurityFilterChain(servletContext);
insertFilters(servletContext,new MultipartFilter(),new MDCFilter());
}
}
最后我们的 Spring Security配置
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
@Configuration
@EnableWebSecurity(debug=true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"select email,pwHash,true from user where email = ?")
.authoritiesByUsernameQuery(
"select email, rolle_rollenname from user where email = ?");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user", "/login", "/logout", "login.html").permitAll()
.anyRequest().authenticated()
.and()
.csrf().csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
.formLogin()
.loginPage("/login")
//.logoutSuccessHandler(new customLogoutSuccessHandler())
.and()
.logout()
.logoutUrl("/logout");
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/scripts/**")
.antMatchers("/stylesheets/**");
}
private CsrfTokenRepository csrfTokenRepository()
{
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
使用自定义身份验证和默认登录页面时,它可以正常运行。 可能是login.html或login.js错误 ...
更新
当我使用.httpBasic()而没有指定loginform时,当我尝试访问安全的资源时会出现一个浏览器对话框。 我想重定向到自定义登录页面而不是浏览器对话框。 怎么办?
答案 0 :(得分:1)
好吧,我是通过使用JSON Web Tokens,一个自定义无状态过滤器并在每次回到前端时将令牌提供给他们的。
答案 1 :(得分:0)
试试这个:
.factory('AuthFactory', ['$http', 'contextPath', '$q', '$timeout', function ($http, contextPath, $q, $timeout) {
function User() {
};
var currentUser = null;
var userChangeCallbacks = [];
var notifyUserChange = function (newUser) {
angular.forEach(userChangeCallbacks, function (callback) {
$timeout(function () {
callback(newUser);
});
});
};
var exported = {
getCurrentUser: function () {
return currentUser;
},
refresh: function () {
return $q(function (resolve, reject) {
//Get the current user
$http.get(contextPath + '/rest/user/current')
.success(function (data) {
currentUser = new User();
for (var key in data) {
currentUser[key] = data[key];
}
notifyUserChange(currentUser);
resolve(currentUser);
})
});
},
registerUserChangeHandler: function (callback) {
console.log("registered handler: " + callback);
userChangeCallbacks.push(callback);
}
};
return exported;
}]);
然后在登录控制器中调用该刷新方法。
登录控制器
$scope.login = function (username, password) {
UserService.login({
'username': username,
'password': password
}, function () {
AuthFactory.refresh();
$state.go("home");
});
};