Spring Boot Security + Vue 登录成功后重定向无 Access-Control-Allow-Origin 问题解决办法
需要明确:
已正确配置跨域资源共享(CORS)(不然也不可能看到登录成功了)。
已正确配置了跨站请求伪造(CSRF)(登录时需要携带 _csrf.token)。
全部使用 POST 提交的数据。
本文相关知识:
MD5 加密与Spring Security 加密介绍。
- 注册时,使用 post 注册,已成功。
- 登录时,已经登录成功,效果如下:
- 前台查看axios响应:
说明:
登录成功与失败,都是响应 JSON 数据。
这里登录成功后,进行了重定向,导致无 Access-Control-Allow-Origin。
附上登录失败的响应:
注:全部使用 POST:
问题说明
出现这种情况,毕竟是少数(其他请求GET/POST等全都正常,目前只发现 Spring Boot Security 登录成功后重定向时出现这种问题)。
响应 JSON 数据解决办法有两种思路:
- 登录成功后进行重定向时,携带 Access-Control-Allow-Origin。
- 登录成功后,不进行重定向,直接响应结果(我这里登录结果全部响应的是JSON数据)。
from 提交数据进行跳转:
- 跳转时在响应中添加 Header 即可。
解决方案:
在 Spring Boot Security 中配置登录成功后,进行自定义处理,接口为:
package org.springframework.security.web.authentication;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.security.core.Authentication;/*** Strategy used to handle a successful user authentication.* <p>* Implementations can do whatever they want but typical behaviour would be to control the* navigation to the subsequent destination (using a redirect or a forward). For example,* after a user has logged in by submitting a login form, the application needs to decide* where they should be redirected to afterwards (see* {@link AbstractAuthenticationProcessingFilter} and subclasses). Other logic may also be* included if required.** @author Luke Taylor* @since 3.0*/
public interface AuthenticationSuccessHandler {/*** Called when a user has been successfully authenticated.** @param request the request which caused the successful authentication* @param response the response* @param authentication the <tt>Authentication</tt> object which was created during* the authentication process.*/void onAuthenticationSuccess(HttpServletRequest request,HttpServletResponse response, Authentication authentication)throws IOException, ServletException;}
通过实现该接口的 onAuthenticationSuccess 方法进行操作。
解决方案一
直接响应 JSON 数据:
代码说明:
在请求(HttpServletRequest request)中获取你需要的Header。
package cn.com.xuxiaowei.passport.handler;import com.alibaba.fastjson.JSON;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;/*** 用于处理成功用户身份验证的策略。** @author xuxiaowei* @since 0.0.1*/
public class LoginAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {Map<String, Object> map = new HashMap<>(4);Map<String, Object> data = new HashMap<>(4);map.put("data", data);map.put("code", 0);map.put("msg", "登录成功");String accessControlAllowOrigin = request.getHeader("Access-Control-Allow-Origin");response.addHeader("Access-Control-Allow-Origin", accessControlAllowOrigin);response.addHeader("Access-Control-Allow-Credentials", "true");response.setContentType("text/json;charset=UTF-8");response.getWriter().println(JSON.toJSON(map));response.setStatus(HttpServletResponse.SC_OK);response.flushBuffer();}}
在 WebSecurityConfigurerAdapter 中配置:
两种方案都需要此配置:
@Overrideprotected void configure(HttpSecurity http) throws Exception {// 其他代码省略// 授权登录成功后处理http.formLogin().successHandler(loginAuthenticationSuccessHandler());}@BeanLoginAuthenticationSuccessHandler loginAuthenticationSuccessHandler() {return new LoginAuthenticationSuccessHandler();}
响应结果:
解决方案二
package cn.com.xuxiaowei.passport.handler;import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 用于处理成功用户身份验证的策略。** @author xuxiaowei* @since 0.0.1*/
public class LoginAuthenticationSuccessHandler implements AuthenticationSuccessHandler {/*** 注意:* 不可设置:response.addHeader("Access-Control-Allow-Credentials", "true");* 否则响应中的的 Access-Control-Allow-Credentials 为:true,true*/@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {String accessControlAllowOrigin = request.getHeader("Access-Control-Allow-Origin");response.addHeader("Access-Control-Allow-Origin", accessControlAllowOrigin);request.getRequestDispatcher("/login/success.do").forward(request, response);}}
注意:
不可设置:response.addHeader("Access-Control-Allow-Credentials", "true");
否则响应中的的 Access-Control-Allow-Credentials 为:true,true;
因为已经存在了 Access-Control-Allow-Credentials 为:true。
虽然有警告,但是这是时数据正常响应的:
不设置 Access-Control-Allow-Credentials 就对了。
在 WebSecurityConfigurerAdapter 中配置同方案一。
效果相同。
解决方案三
如果你使用的是from提交数据进行跳转的话:
package cn.com.xuxiaowei.passport.handler;import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 用于处理成功用户身份验证的策略。** @author xuxiaowei* @since 0.0.1*/
public class LoginAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {String accessControlAllowOrigin = request.getHeader("Access-Control-Allow-Origin");response.addHeader("Access-Control-Allow-Origin", accessControlAllowOrigin);response.addHeader("Access-Control-Allow-Credentials", "true");super.onAuthenticationSuccess(request, response, authentication);}}
相关知识补充
Spring Security 密码加密
/*** Spring Security 密码加密相关测试** @author xuxiaowei* @since 0.0.1*/
public class SpringSecurityTests {/*** 用来测试的密码*/private final String password = "https://xuxiaowei.blog.csdn.net";@Testpublic void passwordEncoder() {// 密码编辑器PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();System.err.println("加密前的密码:" + password);String passwordPncode1 = passwordEncoder.encode(password);String passwordPncode2 = passwordEncoder.encode(password);System.err.println("第一次加密:" + passwordPncode1);System.err.println("第二次加密:" + passwordPncode2);boolean matches1 = passwordEncoder.matches(password, passwordPncode1);boolean matches2 = passwordEncoder.matches(password, passwordPncode2);System.err.println("第一次加密密码比较:" + matches1);System.err.println("第二次加密密码比较:" + matches2);}}
测试结果:
加密前的密码:https://xuxiaowei.blog.csdn.net
第一次加密:{bcrypt}$2a$10$z.E5k6q6MHG9iVN/zRM0FOknS748k5b8gvGp/8njgLjDFZ9GyvcVK
第二次加密:{bcrypt}$2a$10$yosn9iar2ARMikmxLFDy6uYHyEu02DD8NOh/nMgOZJcjKQnWV9EdW
第一次加密密码比较:true
第二次加密密码比较:true
说明:
每次加密,即使是相同的密码,加密后的结果也不会相同。
MD5密码加密
import org.junit.Test;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;/*** MD5 密码解密测试** @author xuxiaowei* @since 0.0.1*/
public class Md5EncodeTests {/*** 用来测试的密码*/private final String password = "123456";@Testpublic void md5() {System.err.println("加密前的密码:" + password);String passwordEncode1 = md5Encode(password);String passwordEncode2 = md5Encode(password);System.err.println("第一次加密:" + passwordEncode1);System.err.println("第二次加密:" + passwordEncode2);boolean equals1 = passwordEncode1.equals(md5Encode(password));boolean equals2 = passwordEncode2.equals(md5Encode(password));System.err.println("第一次加密密码比较:" + equals1);System.err.println("第二次加密密码比较:" + equals2);}/*** MD5 加密** @param text 需要加密的字符串* @return 返回 MD5 加密后的字符串*/private String md5Encode(String text) {try {MessageDigest messageDigest = MessageDigest.getInstance("MD5");messageDigest.update(text.getBytes());byte[] bytes = messageDigest.digest();int i;StringBuilder buf = new StringBuilder();for (byte b : bytes) {i = b;i = i < 0 ? i + 256 : i;if (i < 16) {buf.append("0");}buf.append(Integer.toHexString(i));}return buf.toString();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return null;}}
测试结果:
加密前的密码:123456
第一次加密:e10adc3949ba59abbe56e057f20f883e
第二次加密:e10adc3949ba59abbe56e057f20f883e
第一次加密密码比较:true
第二次加密密码比较:true
说明:
MD5加密,针对同一密码(资源)加密结果每次运行都是一样的。所以出于安全考虑,密码加密不推荐使用 MD5,安全系数低,有泄漏的风险。
若你使用的是简易密码,如:123456,或者两人使用相同的密码,当密码保管不慎泄漏时,后果很严重。
更不要在多个账户中使用同一个密码。
Spring Boot Security + Vue 登录成功后重定向无 Access-Control-Allow-Origin 问题解决办法相关推荐
- Spring Security登录成功后重定向到登陆前页面 解决方案
问题:今天拿security做权限控制的时候,出现了特别灵异的一幕,security配置类写好了,正常登录的情况下,第一次登陆,登陆成功后总会莫名其妙重定向到项目的根路径,但是确实已经登陆成功了,访问 ...
- Spring Boot Security 多种登录方式集成配置思路及方法 账号用户名登录+微信网页授权登录
概述 实现账号用户名+微信网页授权登录集成在Spring Security的思路 前情提要 本思路完全抛弃Spring Security的配置式账号密码登录模式,采用完全独立的Filter.Provi ...
- Spring Security 实战:登录成功后返回 JWT Token
点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 170元买400元书的机会又来啦! 1. 前言 欢迎阅读 Spring Security 实 ...
- Spring Security登录成功后,用户信息保存在哪,如何获取?
当前用户获取信息 我们在SecurityContextHolder内存储目前与应用程序交互的主要细节.Spring Security使用一个Authentication对象来表示这些信息. 你通常不需 ...
- (二)Spring Security自定义登录成功或失败处理器
目录 一:创建登录成功处理器 二:创建登录失败处理器 三:添加处理器 三. 项目地址 我们接着上一章 Spring Security最简单的搭建,进行开发 LoginSuccessHandler 和L ...
- Vue项目登录成功后返回到原操作页面
登录超时或者由于其它原因,造成必须重新登录的情况,相信大家都见过这种场景,比较偷懒的办法是登陆成功厚直接回到主页面,但其实我们有更好的解决办法. 作为vue的标配,我们可以利用axios的全局拦截器做 ...
- spring boot security 将您重定向的次数过多
在学习spring boot security的过程中遇到了这样的一个问题. 查看代码,为了跳转到我们自己定义的登录页面,写了loginPage("/login.html"),按照 ...
- Spring Boot 实现单点登录的第三种方案!
前面松哥发过两篇文章,也是两种方案,讲到单点登录问题: OAuth2+JWT 方案 @EnableOAuth2Sso 注解方案 今天再来和大家介绍第三种方案,使用 Spring Security 开发 ...
- 《深入理解 Spring Cloud 与微服务构建》第十六章 Spring Boot Security 详解
<深入理解 Spring Cloud 与微服务构建>第十六章 Spring Boot Security 详解 文章目录 <深入理解 Spring Cloud 与微服务构建>第十 ...
最新文章
- Udacity机器人软件工程师课程笔记(二十五) - 使用PID控制四轴飞行器 - 四轴飞行器(四旋翼)模拟器
- java架构师,必须掌握的几点技术?
- python使用字典实现switch_python之 利用字典与函数实现switch case功能
- html+单选+回显,VUE+elementUI表格多选框实现单选以及数据回显时toggleRowSelection失效问题...
- RabbitMQ 队列消息持久化
- 微信公众平台网站开发JS_SDK遇到的bug——wx.config注册提示成功,但部分接口注册失败问题
- wp8.1 Study11:APP里文件读写和使用XML和Json序列化
- 库克:iPhone 11在中国定价策略很成功 非常受欢迎
- linux汇编指令输出到屏幕,Linux 汇编语言(GNU GAS汇编)开发指南
- 冲刺阶段—个人工作总结07
- 分析QQ和QQ游戏的价值特性极其快速发展的原因,并对其盈利模式进行探讨
- mysql 等待函数,mysql 函数
- 下载m3u8视频及在Linux下将ts合并为mp4格式
- LTspice基础教程-008.LTspice PWL设置
- Excel如何将数据拆分开
- QT:表格操作QTableView详解
- QMC5883L磁力计驱动
- 基于HTML+JS实现的简易双色球滚动代码
- MacBook Pro M1 安装Homebrew记录
- python使用py2neo操作neo4j
热门文章
- 给 Android 开发者的 Flutter 指南(上)
- 互联网日报 | 理想汽车登陆纳斯达克;苏宁易购会员数量突破6亿;高德地图上线“司机公厕”...
- 安卓 视频 分辨率、帧率和码率三者之间的关系
- Windows 10 专业版高对比度开了之后怎么调回去?
- 【博弈论/思维题】人人尽说江南好
- 如何围绕企业战略,建设BI驾驶舱?
- Maven构建的生命周期详解
- 花呗额度快充显示服务器调整,花呗有新变化,快充额度被关闭,还能快速提额吗?...
- matlab rbe神经网络代码,径向基神经网络知识介绍
- 智慧楼宇系统如何帮助产业园区破解招商难题?