我试图在另一个应用程序(spring-boot应用程序)上调用REST endpoints (angularjs) . 应用程序在以下主机和端口上运行 .
-
REST应用程序,使用spring boot,
http://localhost:8080
-
HTML应用程序,使用angularjs,
http://localhost:50029
我也在使用带有spring-boot应用程序的 spring-security
. 从HTML应用程序,我可以对REST应用程序进行身份验证,但此后,我仍然无法访问任何REST endpoints . 例如,我有一个如下定义的angularjs服务 .
adminServices.factory('AdminService', ['$resource', '$http', 'conf', function($resource, $http, conf) {
var s = {};
s.isAdminLoggedIn = function(data) {
return $http({
method: 'GET',
url: 'http://localhost:8080/api/admin/isloggedin',
withCredentials: true,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
};
s.login = function(username, password) {
var u = 'username=' + encodeURI(username);
var p = 'password=' + encodeURI(password);
var r = 'remember_me=1';
var data = u + '&' + p + '&' + r;
return $http({
method: 'POST',
url: 'http://localhost:8080/login',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
};
return s;
}]);
angularjs控制器如下所示 .
adminControllers.controller('LoginController', ['$scope', '$http', 'AdminService', function($scope, $http, AdminService) {
$scope.username = '';
$scope.password = '';
$scope.signIn = function() {
AdminService.login($scope.username, $scope.password)
.success(function(d,s) {
if(d['success']) {
console.log('ok authenticated, call another REST endpoint');
AdminService.isAdminLoggedIn()
.success(function(d,s) {
console.log('i can access a protected REST endpoint after logging in');
})
.error(function(d, s) {
console.log('huh, error checking to see if admin is logged in');
$scope.reset();
});
} else {
console.log('bad credentials?');
}
})
.error(function(d, s) {
console.log('huh, error happened!');
});
};
}]);
在调用 http://localhost:8080/api/admin/isloggedin
时,我得到一个 401 Unauthorized
.
在REST应用程序方面,我有一个CORS过滤器,如下所示 .
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
@Override
public void destroy() { }
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:50029");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) {
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig config) throws ServletException { }
}
我的spring安全配置如下所示 .
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private JsonAuthSuccessHandler jsonAuthSuccessHandler;
@Autowired
private JsonAuthFailureHandler jsonAuthFailureHandler;
@Autowired
private JsonLogoutSuccessHandler jsonLogoutSuccessHandler;
@Autowired
private AuthenticationProvider authenticationProvider;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PersistentTokenRepository persistentTokenRepository;
@Value("${rememberme.key}")
private String rememberMeKey;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/", "/admin", "/css/**", "/js/**", "/fonts/**", "/api/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(jsonAuthSuccessHandler)
.failureHandler(jsonAuthFailureHandler)
.permitAll()
.and()
.logout()
.deleteCookies("remember-me", "JSESSIONID")
.logoutSuccessHandler(jsonLogoutSuccessHandler)
.permitAll()
.and()
.rememberMe()
.userDetailsService(userDetailsService)
.tokenRepository(persistentTokenRepository)
.rememberMeCookieName("REMEMBER_ME")
.rememberMeParameter("remember_me")
.tokenValiditySeconds(1209600)
.useSecureCookie(false)
.key(rememberMeKey);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
}
所有处理程序正在做的是基于用户是否登录,无法进行身份验证或注销而写出JSON响应,如 {success: true}
. RestAuthenticationEntryPoint
如下所示 .
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex)
throws IOException, ServletException {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
关于我遗失或做错的任何想法?
8 回答
无需额外定义此过滤器只需添加此类 . Spring将扫描并为您添加它 . SimpleCORSFilter . 这是一个例子:spring-enable-cors
我曾经遇到过类似的情况 . 经过研究和测试,这是我的发现:
@CrossOrigin
配置结合使用:Here是非常优秀的教程,解释了Spring MVC框架中的CORS支持 .
这对我有用:
如果你想在不使用过滤器或没有配置文件的情况下启用CORS,只需添加即可
到你的控制器顶部,它的工作原理 .
对我来说,使用 spring 安全时唯一能够100%工作的是跳过所有额外过滤器和 beans 子的额外毛茸茸以及任何间接的“神奇”人们一直暗示这对他们有用但不适合我 .
相反,只需强制它使用普通
StaticHeadersWriter
编写所需的 Headers :这是我发现的最直接,最明确的方式 . 希望它可以帮助某人 .
检查一下:
扩展WebSecurityConfigurerAdapter类并覆盖@EnableWebSecurity类中的configure()方法将起作用:下面是示例类
如果最初您的程序不使用spring安全性并且无法承担代码更改,那么创建一个简单的反向代理就可以解决问题 . 就我而言,我使用Nginx进行以下配置:
我的程序监听 :8080 .
REF:CORS on Nginx