我试图在Spring中建立一个后端,在Vue中建立一个前端。同一台机器,分开的项目。我解决或禁用了所有的cors,csrf和登录问题,但这一个让我完全飘飘欲仙。
Spring :SecurityConfig.java
package main.java.it.coderevo.security.config;
import java.util.Arrays;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Autowired
@Qualifier("allowedOrigin")
String allowedOriginDev;
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication().dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery(
" SELECT username, password, enabled "
+ " FROM User where username = ?"
)
.authoritiesByUsernameQuery(
" SELECT username, Role.name as 'role' "
+ " FROM User "
+ " JOIN Role ON User.idRole = Role.id "
+ " WHERE username = ?"
);
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/god**").hasRole("GOD")
.antMatchers("/admin**").hasAnyRole("ADMIN", "GOD")
.antMatchers("/api**").hasAnyRole("USER", "ADMIN", "GOD")
.antMatchers("/login**").permitAll()
.antMatchers("/public**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.and()
.cors()
.and()
.formLogin().disable()
.csrf().disable().httpBasic();
}
// To enable CORS
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedOrigins(Arrays.asList(allowedOriginDev));
configuration.setAllowedMethods(Arrays.asList(
RequestMethod.GET.name(),
RequestMethod.POST.name()
));
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "Cache-Control"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
和LoginController.java:
package main.java.it.coderevo.controller;
import java.security.Principal;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import main.java.it.coderevo.algo.Helper;
import main.java.it.coderevo.pojo.User;
@RestController
@RequestMapping("/login*")
public class LoginController {
@Autowired
private Helper helper;
@RequestMapping(method = { RequestMethod.GET, RequestMethod.POST},
produces = "application/json")
String getUserInfo(Principal principal) {
JSONObject json = new JSONObject();
User user = helper.getLoggedUser(principal);
json.put("logged", user != null);
if (user == null)
json
.put("msg", "error looking for user info!");
else
json
.put("username", user.getUsername())
.put("mail", user.getMail())
.put("verified", user.isVerified())
.put("role", user.getRole().getName());
return json.toString();
}
}
在另一边,我们发现一个经典的API axios:
api.login(this.usr, this.pws)
.then( res => this.loginPass(res))
.catch(err => this.loginError(err));
在库中解析:
login: (usr, pws) => {
let conf = {
withCredentials: true
}
if (usr && pws)
conf.headers = {
'Authorization': "Basic " + btoa(usr + ":" + pws)
}
return server.post(SERVER_URL + "login", {}, conf)
}
然后,重点:都在工作;登录、注销、cookie......但如果我发布了一些未经授权的凭据,服务器会给我一个超时错误,而不是报告发生了什么:
Error: timeout of 1000ms exceeded
at createError (createError.js?2d83:16)
at XMLHttpRequest.handleTimeout (xhr.js?b50d:95)
而且Vue也向我展示了一种有点奇怪行为:x1c 0d1x正如您可以从当我发送axios post请求到当请求超时(默认值是1秒,但修改该值只会导致警报形式变短或变长)中看到,由于某种原因,出现了bad-ugly-old-school-alert-form,我无法休息。
作为一个人,至少我可以开始挖掘一些方向?我其实真的很困惑。
更新1
主要问题似乎是在axios调用中,特别是withCredentials: true
。我使用该选项的主要原因是处理现成的会话cookie。禁用该选项会导致正常的登录行为(但没有会话管理),启用该选项会给我带来不受欢迎的丑陋形式,我不能把我的手。
1条答案
按热度按时间fsi0uk1n1#
在最后一个例子中,这就是重点:axios向API发布了一个带有错误用户名和/或密码的请求。服务器重放401,
XXX-Authenticate
头设置为Authentication: Basic realm
。Google Chrome武断地决定在axios超时之前用一个提示来处理这种情况。
因此,更简单的解决方案是修改服务器重放的这2个信息中的至少一个:您可以使用不同的状态代码(例如400或403),但最好的方法是保留401代码(401的含义是
unauthorized request
),并避免在XXX-Authentication
报头中使用身份验证部分。这是一个简单的身份验证入口点,在 Spring 附加到我的
httpBasic()
,似乎可以解决以下问题:!!
super.commence(request, response, authException)
调用导致无用的忽略响应修改,因此请避免!!