需要明确:

已正确配置跨域资源共享(CORS)(不然也不可能看到登录成功了)。

已正确配置了跨站请求伪造(CSRF)(登录时需要携带 _csrf.token)。

全部使用 POST 提交的数据。


本文相关知识:

MD5 加密与Spring Security 加密介绍。


  1. 注册时,使用 post 注册,已成功。
  2. 登录时,已经登录成功,效果如下:
  3. 前台查看axios响应:
    说明:
    登录成功与失败,都是响应 JSON 数据。
    这里登录成功后,进行了重定向,导致无 Access-Control-Allow-Origin。

    附上登录失败的响应:
    注:全部使用 POST:

问题说明

出现这种情况,毕竟是少数(其他请求GET/POST等全都正常,目前只发现 Spring Boot Security 登录成功后重定向时出现这种问题)。

响应 JSON 数据解决办法有两种思路:

  1. 登录成功后进行重定向时,携带 Access-Control-Allow-Origin。
  2. 登录成功后,不进行重定向,直接响应结果(我这里登录结果全部响应的是JSON数据)。

from 提交数据进行跳转:

  1. 跳转时在响应中添加 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 问题解决办法相关推荐

  1. Spring Security登录成功后重定向到登陆前页面 解决方案

    问题:今天拿security做权限控制的时候,出现了特别灵异的一幕,security配置类写好了,正常登录的情况下,第一次登陆,登陆成功后总会莫名其妙重定向到项目的根路径,但是确实已经登陆成功了,访问 ...

  2. Spring Boot Security 多种登录方式集成配置思路及方法 账号用户名登录+微信网页授权登录

    概述 实现账号用户名+微信网页授权登录集成在Spring Security的思路 前情提要 本思路完全抛弃Spring Security的配置式账号密码登录模式,采用完全独立的Filter.Provi ...

  3. Spring Security 实战:登录成功后返回 JWT Token

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 170元买400元书的机会又来啦! 1. 前言 欢迎阅读 Spring Security 实 ...

  4. Spring Security登录成功后,用户信息保存在哪,如何获取?

    当前用户获取信息 我们在SecurityContextHolder内存储目前与应用程序交互的主要细节.Spring Security使用一个Authentication对象来表示这些信息. 你通常不需 ...

  5. (二)Spring Security自定义登录成功或失败处理器

    目录 一:创建登录成功处理器 二:创建登录失败处理器 三:添加处理器 三. 项目地址 我们接着上一章 Spring Security最简单的搭建,进行开发 LoginSuccessHandler 和L ...

  6. Vue项目登录成功后返回到原操作页面

    登录超时或者由于其它原因,造成必须重新登录的情况,相信大家都见过这种场景,比较偷懒的办法是登陆成功厚直接回到主页面,但其实我们有更好的解决办法. 作为vue的标配,我们可以利用axios的全局拦截器做 ...

  7. spring boot security 将您重定向的次数过多

    在学习spring boot security的过程中遇到了这样的一个问题. 查看代码,为了跳转到我们自己定义的登录页面,写了loginPage("/login.html"),按照 ...

  8. Spring Boot 实现单点登录的第三种方案!

    前面松哥发过两篇文章,也是两种方案,讲到单点登录问题: OAuth2+JWT 方案 @EnableOAuth2Sso 注解方案 今天再来和大家介绍第三种方案,使用 Spring Security 开发 ...

  9. 《深入理解 Spring Cloud 与微服务构建》第十六章 Spring Boot Security 详解

    <深入理解 Spring Cloud 与微服务构建>第十六章 Spring Boot Security 详解 文章目录 <深入理解 Spring Cloud 与微服务构建>第十 ...

最新文章

  1. Udacity机器人软件工程师课程笔记(二十五) - 使用PID控制四轴飞行器 - 四轴飞行器(四旋翼)模拟器
  2. java架构师,必须掌握的几点技术?
  3. python使用字典实现switch_python之 利用字典与函数实现switch case功能
  4. html+单选+回显,VUE+elementUI表格多选框实现单选以及数据回显时toggleRowSelection失效问题...
  5. RabbitMQ 队列消息持久化
  6. 微信公众平台网站开发JS_SDK遇到的bug——wx.config注册提示成功,但部分接口注册失败问题
  7. wp8.1 Study11:APP里文件读写和使用XML和Json序列化
  8. 库克:iPhone 11在中国定价策略很成功 非常受欢迎
  9. linux汇编指令输出到屏幕,Linux 汇编语言(GNU GAS汇编)开发指南
  10. 冲刺阶段—个人工作总结07
  11. 分析QQ和QQ游戏的价值特性极其快速发展的原因,并对其盈利模式进行探讨
  12. mysql 等待函数,mysql 函数
  13. 下载m3u8视频及在Linux下将ts合并为mp4格式
  14. LTspice基础教程-008.LTspice PWL设置
  15. Excel如何将数据拆分开
  16. QT:表格操作QTableView详解
  17. QMC5883L磁力计驱动
  18. 基于HTML+JS实现的简易双色球滚动代码
  19. MacBook Pro M1 安装Homebrew记录
  20. python使用py2neo操作neo4j

热门文章

  1. 给 Android 开发者的 Flutter 指南(上)
  2. 互联网日报 | 理想汽车登陆纳斯达克;苏宁易购会员数量突破6亿;高德地图上线“司机公厕”...
  3. 安卓 视频 分辨率、帧率和码率三者之间的关系
  4. Windows 10 专业版高对比度开了之后怎么调回去?
  5. 【博弈论/思维题】人人尽说江南好
  6. 如何围绕企业战略,建设BI驾驶舱?
  7. Maven构建的生命周期详解
  8. 花呗额度快充显示服务器调整,花呗有新变化,快充额度被关闭,还能快速提额吗?...
  9. matlab rbe神经网络代码,径向基神经网络知识介绍
  10. 智慧楼宇系统如何帮助产业园区破解招商难题?