我有一个 Java Springboot REST api,我也尝试从 ionic4 Web 应用程序发送 POST 请求。不幸的是我无法让登录后工作。当它仅发送预检选项请求时,我会收到 HTTP 状态 401
、403
或 200
。
我在 StackOverflow 上检查过类似的帖子,例如 this但他们刚刚改变了我收到的错误。下面是我从各种教程和其他 SO 帖子中获取一些信息后得到的结果。
不确定我的错误是否与 Spring SecurityConfiguration 或 TypeScript post 请求有关。
我的 Spring 安全配置
@EnableWebSecurity
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableGlobalMethodSecurity(securedEnabled = true)
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers("/login").permitAll()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new RestConfig().corsFilter(), CsrfFilter.class)
.csrf().csrfTokenRepository(csrfTokenRepository()).and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.formLogin().loginProcessingUrl("/login")
.successHandler(successHandler())
.failureHandler(failureHandler())
.and()
.exceptionHandling()
.and()
.csrf().disable();
}
private AuthenticationSuccessHandler successHandler() {
return new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.getWriter().append("OK");
httpServletResponse.setStatus(200);
}
};
}
private AuthenticationFailureHandler failureHandler() {
return new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.getWriter().append("Authentication failure");
httpServletResponse.setStatus(401);
}
};
}
private AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.getWriter().append("Access denied");
httpServletResponse.setStatus(403);
}
};
}
private AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.getWriter().append("Not authenticated");
httpServletResponse.setStatus(401);
}
};
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null
&& !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Credentials", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
repository.setSessionAttributeName("_csrf");
return repository;
}
我的 TypeScript POST
onLogin(loginData: {username: string, password: string}) {
let headers = new Headers();
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('Content-Type','application/x-www-form-urlencoded');
headers.append("Authorization", "Basic " + btoa(loginData.username + ":" + loginData.password));
let body = {
username: loginData.username,
password: loginData.password
}
this.http.post('http://localhost:5000/login', body, {headers: headers, withCredentials: true})
.map(res => res.json())
.subscribe(data => {
console.log(data);
console.log(data.status)
});
}
}
上面的代码出现错误,我知道这不是登录详细信息,因为相同的用户名和密码可以通过 swagger 完美地工作,只是不在 POST 中。
最佳答案
这就是我解决问题的方法。
onLogin(loginData: {username: string, password: string}) {
let headers = new Headers();
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('Content-Type','application/x-www-form-urlencoded');
let body = `username=${loginData.username}&password=${loginData.password}`;
this.http.post('http://localhost:5000/login', body, {headers: headers})
.map(res => res)
.subscribe(data => {
console.log(data.status);
if (data.status == 200) {
this.navCtrl.push(TabsPage);
}
else {
this.showError("Invalid username or password");
}
});
}
更新: 主要问题是 URL-encoding这一行:
let body = `username=${loginData.username}&password=${loginData.password}`;
感谢dur
关于Java Spring Security ionic4 HTTP 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44556251/