本人的前后端项目是这样的:
前端:http://localhost:5173
后端: http://localhost:9001,并且使用了spring security,配置了允许跨域,而且可以实现前后端分离登录。
后端部分代码如下(有的代码是参考了别的大神)
package com.example.demo.config;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private UsersService usersService;
@Autowired
VerificationCodeFilter verificationCodeFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**","/js/**","/css/**","/img/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(verificationCodeFilter, UsernamePasswordAuthenticationFilter.class); //用于校验验证码的filter
http.authorizeRequests()
.antMatchers("/sms/system/getVerifiCodeImage").permitAll()
.anyRequest().authenticated()
.and()
// 表单登录
.formLogin()
// 登录成功处理(对应流程2)
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map map = new HashMap();
String token = usersService.GenerateTokenByUserName(((User)authentication.getPrincipal()).getUsername());
map.put("token", token);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(
JSON.toJSONString(Result.ok(map)));
}
})
// 登录失败处理(对应流程3)
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(
JSON.toJSONString(Result.fail().message("登录失败")));
}
})
.and()
//登出
.logout()
//登出成功处理
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(
JSON.toJSONString(Result.ok()));
}
})
.and()
//异常处理
.exceptionHandling()
//未登录处理
.authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(Result.fail()));
}
})
//没有权限处理
.accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(Result.fail()));
}
})
.and().cors()
.and()
.csrf().disable();
}
@Bean
PasswordEncoder password(){return new BCryptPasswordEncoder();}
@Bean
CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许跨域访问的站点
corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:5173"));
//允许跨域访问的methods
corsConfiguration.setAllowedMethods(Arrays.asList("GET","POST"));
// 允许携带凭证
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//对所有URL生效
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
}
VerificationCodeFilter:
package com.example.demo.Filter;
//验证码校验
@Component
public class VerificationCodeFilter extends GenericFilter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if("POST".equals(request.getMethod()) && "/login".equals(request.getServletPath()))
{
HttpSession session = request.getSession();
String sessionVerifiCode = (String)session.getAttribute("verifiCode");
String loginVerifiCode = request.getParameter("verifiCode");
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
if(sessionVerifiCode.equals("")||sessionVerifiCode==null)
{
out.write(JSON.toJSONString(Result.fail().message("验证码失效,请刷新后重试")));
out.flush();
out.close();
return;
}
else if(!sessionVerifiCode.equalsIgnoreCase(loginVerifiCode))
{
out.write(JSON.toJSONString(Result.fail().message("验证码有误,请小心输入后重试")));
out.flush();
out.close();
return;
}
else
{
session.removeAttribute("verifiCode");
filterChain.doFilter(request,response);
}
}
else
{
filterChain.doFilter(request,response);
}
}
}
MyUserDetailsServices:
package com.example.demo.service.Impl;
@Service("userDetailsService")
public class MyUserDetailsServices implements UserDetailsService {
@Autowired
private UsersMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
Users users = usersMapper.selectOne(wrapper);
if(users == null)
{
throw new UsernameNotFoundException("用户名不存在");
}
List auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new User(users.getUsername(),
new BCryptPasswordEncoder().encode(users.getPassword()), auths);
}
}
前端部分代码:
axios({
method: 'post',
url: 'http://localhost:9001/login',
//header:{'content-type': 'application/x-www-form-urlencoded'},
data: qs.stringify({
username: loginform.username,
password: loginform.userpassword,
verifiCode: loginform.verifycode/*,
userType: loginform.usertype*/
})
}).then(response => {
console.log(response);
if(response.data.code == "200" && response.data.ok)
{
document.cookie="token="+response.data.data.token;
router.push('/bursary')
}
else{
ElMessage({
showClose: true,
message: response.data.message,
type: 'warning',
duration : 1000
});
refreshVerifyCode();
}
}).catch(function (error) {
console.log(error);
refreshVerifyCode();
});
目前的问题是,登录时没有跨域问题,验证码也能正常显示。但是我一旦通过router跳转到其他vue文件,就出现跨域问题,如下图。
我试着给跳转后需要请求的controller添加@CrossOrigin,仍然解决不了。
抓狂之下,只有死马当活马医,用最后的办法,vue设置代理服务器:
打开vite.config.js文件,
defineConfig里添加如下代码:
server:
{
proxy:{
'/api':{
target:'http://localhost:9001',
changeOrigin:true,
rewrite: (path)=>path.replace(/^\/api/,'')
}
}
}
然后将前端所有的请求,从http://localhost:9001换成 api:
axios({
method: 'post',
url: '/api/login',
然后,问题解决了~~~
如果你也遇到这操蛋的问题,希望这篇文章能帮助到你