在我的 Web 应用程序中集成 Spring Security(即登录部分)时遇到了一些问题。我的后端在 localhost:8080 上运行,而前端(Ionic 2 和 AngularJS 2)在 localhost:8100 上运行。我设法登录(至少我是这么认为的),但其余请求不可用,并且我在 Chrome 开发者控制台中收到以下错误:
XMLHttpRequest cannot load http://localhost:8080/company/getAll. Response for preflight is invalid (redirect)
当使用 Postman 进行测试时,它似乎工作正常,我登录,然后可以在 http://localhost:8080/company/getAll 上执行 POST 请求。一切都按预期工作。
大概我错过了一些东西(比如 token ),但不知道是什么。我是 Ionic 和 Spring Security 的新手,所以如果这是微不足道的,请原谅我。我尝试在谷歌上搜索各种教程,但找不到任何东西(其中大多数都使用 JSP)。
我怎样才能让它工作?我的前端请求应该是什么样子?
这是我从后端 Controller 登录的方法:
@RequestMapping(value = "/login", method = RequestMethod.GET)
@CrossOrigin(origins = "*")
public ResponseEntity<GeneralResponse> login(Model model, String error, String logout) {
System.out.println("LOGIN"+model.toString());
if (error != null) {
System.out.println("1.IF");
model.addAttribute("error", "Your username and password is invalid.");
}
if (logout != null) {
System.out.println("2.IF");
model.addAttribute("message", "You have been logged out successfully.");
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new GeneralResponse(true, "FAILURE: Error"));
}
这是我的 WebSecurityConfig:
@Configuration
@EnableWebSecurity
@ComponentScan("com.SAB.service")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/user/login")
.permitAll()
.and()
.logout()
.permitAll();
http
.csrf().disable();
http.formLogin().defaultSuccessUrl("http://localhost:8100/", true);
//.and().exceptionHandling().accessDeniedPage("/403")
//.and().sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
最后是我负责登录的前端代码:
login(){
var body = 'username='+this.loginForm.controls['username'].value+'&password='+this.loginForm.controls['password'].value;
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
//headers.append("Access-Control-Allow-Origin", "*");
this.http
.post('http://localhost:8080/user/login',
body, {
headers: headers
})
.subscribe(data => {
console.log('ok');
console.log(data)
}, error => {
console.log(JSON.stringify(error.json()));
});
}
如果您需要任何其他详细信息,请告诉我,我会提供。
提前致谢!
我没有收到 Access-CONtroll-Origin 错误,但我还是尝试根据评论更改它,现在我收到“无效的 CORS 请求”
编辑: 这是 Spring Security 日志。然而 Spring 只注册一个 OPTIONS 请求,没有 POST,即使 FrontEnd 正在调用 POST。
************************************************************
Request received for OPTIONS '/login':
org.apache.catalina.connector.RequestFacade@18859793
servletPath:/login
pathInfo:null
headers:
host: localhost:8080
connection: keep-alive
access-control-request-method: POST
origin: http://localhost:8100
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36
access-control-request-headers: access-control-allow-origin
accept: */*
referer: http://localhost:8100/
accept-encoding: gzip, deflate, sdch, br
accept-language: en-US,en;q=0.8
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2017-05-12 19:18:28.527 DEBUG 16500 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /login at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2017-05-12 19:18:28.527 DEBUG 16500 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /login at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2017-05-12 19:18:28.527 DEBUG 16500 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2017-05-12 19:18:28.527 DEBUG 16500 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2017-05-12 19:18:28.529 DEBUG 16500 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /login at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2017-05-12 19:18:28.529 DEBUG 16500 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : /login at position 4 of 12 in additional filter chain; firing Filter: 'CorsFilter'
2017-05-12 19:18:28.541 DEBUG 16500 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5baaaa2b
2017-05-12 19:18:28.541 DEBUG 16500 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2017-05-12 19:18:28.541 DEBUG 16500 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
更新:
因此,在接受的答案中添加建议的 CORSFilter 后,我还必须在前端修改我的请求,以便在每个请求上发送带有 JSESSIONID 的 cookie。基本上我必须将以下内容添加到我的所有请求中:
let options = new RequestOptions({ headers: headers, withCredentials: true });
最佳答案
这似乎是与 CORS 配置相关的问题。浏览器确实会在您的实际 GET 调用之前发出 OPTION 预检请求。我在这方面的知识不多,但是您可以尝试将下面的过滤器添加到 Spring 后端。
public class CORSFilter extends GenericFilterBean {
public void doFilter(ServletRequest request, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse response = (HttpServletResponse) res;
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.addHeader("Access-Control-Max-Age", "3600");
response.addHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
response.addHeader("Access-Control-Allow-Credentials", "true");
if(req.getMethod().equalsIgnoreCase("options")){
return;
}
chain.doFilter(request, response);
}
}
并在您的 WebSecurityConfig 的 configure 方法中添加以下行。
.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class);
关于java - 使用 Java 和 Angular2 进行 Spring Security 登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43875137/