SpringSecurity源码分析以及如何解决前后端分离出现的跨域问题

解决Security前后端分离出现的跨域问题

一. Security源码分析

首先在看源码之前我们先来看这张图 , 这张图展示了Security执行的全部流程

在这里插入图片描述

从上图可知Security执行的入口是UsernamePasswordAuthenticationFilter这个抽象类 , 那我们就先从该类进行分析

1. UsernamePasswordAuthenticationFilter

在这里插入图片描述

进入源码我们可以看到该类继承了一个叫做AbstractAuthenticationProcessingFilter的类 , 而相同的是二者的类名都包含Filter , 说明二者的顶级接口都包含Filter , 而Filter中包含一个非常重要的方法doFilter , 但是作为抽象重写该方法不是必须的 , 现在我们就从继承的层级关系寻找哪个类重写了该方法

AbstractAuthenticationProcessingFilter

在这里插入图片描述

该类继承了一个GenericFilterBean抽象类 , 我们继续往上找

GenericFilterBean

在这里插入图片描述

在这里我们终于找到了Filter接口 , 那么谁重写了doFilter呢? ( 这里的是否被重写需要从上层一层一层往下找 )

在这里插入图片描述

点开结构我们发现这里并没有发现doFilter , 那么就看它的下一级嘛 , 也就是AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter

在这里插入图片描述

在这里我们也是找到了doFilter方法 , 观察其源码该方法调用了一个叫做attemptAuthentication尝试认证的方法

在这里插入图片描述

而该方法是一个抽象方法 , 必然会被子类重写 , 那么绕来绕去又要回到一开始的UsernamePasswordAuthenticationFilter

2. attemptAuthentication

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (this.postOnly && !request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());} else {String username = this.obtainUsername(request);username = username != null ? username : "";username = username.trim();String password = this.obtainPassword(request);password = password != null ? password : "";UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);this.setDetails(request, authRequest);return this.getAuthenticationManager().authenticate(authRequest);}
}

如下所示 , 前端传输的账号与密码是通过obtainUsername这个方法进行获取的 , 那么继续来看该方法做了什么在这里插入图片描述

    @Nullableprotected String obtainUsername(HttpServletRequest request) {return request.getParameter(this.usernameParameter);}
private String usernameParameter = "username";private String passwordParameter = "password";

看完下面的代码是不是很明确了 , 账号密码是通过request.getParameter获取的而该方法 , 而该方法是获取表单数据的 , 在前后端分离的架构中拥有跨域问题 , 所以传统的Security架构无法解决这些问题 , 就需要我们自己来实现

二. 如何重写attemptAuthentication方法 , 实现数据传输

重写attemptAuthentication我们只需要继承AbstractAuthenticationProcessingFilter类并参照UsernamePasswordAuthenticationFilter原有的方法进行重新, 进行适当的修改即可

package com.itheima.security.filter;import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;/*** @program: security_demo* @description:* @author: jixu* @create: 2024-10-18 01:40**/public class MyUserNamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {protected MyUserNamePasswordAuthenticationFilter(String defaultFilterProcessesUrl) {super(defaultFilterProcessesUrl);}public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";@Overridepublic Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {if (!httpServletRequest.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + httpServletRequest.getMethod());} else {// 在这里就是出现问题的地方只需要重新修改获取账号密码的方式就行了// 这里由于我使用的是Json格式的数据进行传参 , 所以只需要获取数据, 反序列化即可ServletInputStream inputStream = httpServletRequest.getInputStream();HashMap<String,String> info = new ObjectMapper().readValue(inputStream, HashMap.class);String username = info.get(SPRING_SECURITY_FORM_USERNAME_KEY);username = username != null ? username : "";username = username.trim();String password = info.get(SPRING_SECURITY_FORM_PASSWORD_KEY);password = password != null ? password : "";UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);//this.setDetails(httpServletRequest, authRequest);return this.getAuthenticationManager().authenticate(authRequest);}}/**** @param request* @param response* @param chain* @param authResult: 用户认证信息* @throws IOException* @throws ServletException*/@Overrideprotected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {User principal = (User) authResult.getPrincipal();String username = principal.getUsername();Collection<GrantedAuthority> authorities = principal.getAuthorities();response.setContentType(MediaType.APPLICATION_JSON_VALUE);HashMap<String, String> info = new HashMap<>();info.put("code","1");info.put("msg","响应成功");// 将数据Map数据序列化成Json数据并发送response.getWriter().write(new ObjectMapper().writeValueAsString(info));}@Overrideprotected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {super.unsuccessfulAuthentication(request, response, failed);}
}

在这里我们已经将自定义的配置信息完善了 , 那么接下来再来想一个问题 , 该配置信息如何被Security识别并使用?

在Security中先来的过滤器会覆盖后来的 , 也就是当识别到一个过滤器被使用了 , 那么它后面与之相同的过滤器就会失效

所以只需要提前声明我们自定义的过滤器就行了

package com.itheima.security.config;import com.itheima.security.filter.MyUserNamePasswordAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
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.security.web.authentication.UsernamePasswordAuthenticationFilter;/*** @program: security_demo* @description:* @author: jixu* @create: 2024-10-17 21:01**/@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}/*** 定义用户认证和授权的信息* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin().and().logout().permitAll().and().csrf().disable().authorizeRequests();http.addFilterBefore(myUserNamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}@Beanpublic MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter() throws Exception {// 构造认证过滤器对象 , 传入默认登录路径MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter = new MyUserNamePasswordAuthenticationFilter("/mylogin");// 认证该过滤器BeanmyUserNamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());return myUserNamePasswordAuthenticationFilter;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/453136.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jmeter简介

基础介绍 Jmeter录制脚本的原始是配置一个HTTP代理&#xff0c;然后浏览器通过这个代理访问测试页面从而完成脚本录制。 一、下载安装 jmeter本身不需要安装&#xff0c;需要配置环境变量JDK&#xff0c;然后打开bin文件夹中的jmeter.vbs即可。建议jdk 1.7及以上版本。 基本祖…

Python+Flask接口判断身份证省份、生日、性别、有效性验证+docker部署+Nginx代理运行

这里写目录标题 一、接口样式二、部署流程2.1 镜像打包2.1.1 准备工作2.1.2 build打包2.1.3 dokcer部署运行2.1.4 Nginx代理 三、代码及文件3.1 index.py3.2 areaCodes.json3.3 Dockerfile 一、接口样式 https://blog.henryplus.cn/idcardApi/idCard/query?idcard{idcard} 如果…

1.计算机网络_基本知识

基本知识 计算机网络的类别&#xff1a; 1、按作用范围来分类 2、按网络的使用者来分类 什么是计算机网络&#xff1a; 计算机网络由若干个节点和链接这些节点的链路组成&#xff0c;节点可以是计算机、集线器、交换机、路由器等。互联网络是多个网络通过路由器连接在了一起…

c语言基础程序——经典100道实例。

c语言基础程序——经典100道实例 001&#xff0c; 组无重复数字的数002&#xff0c;企业发放的奖金根据利润提成003&#xff0c;完全平方数004&#xff0c;判断当天是这一年的第几天005&#xff0c;三个数由小到大输出006&#xff0c;输出字母C图案007&#xff0c;特殊图案008&…

尊享挚爱之选:三好夫人高端养生茶,不仅仅是茶,更是爱的传递

三好夫人&#xff1a;吾扶丈夫凌云志&#xff0c;夫还贤妻万两金&#xff01; 在追求品质生活的道路上&#xff0c;一份贴心、高端的礼物&#xff0c;不仅能彰显品味&#xff0c;更能传递深情厚意。今天&#xff0c;就让我们一起走进“三好夫人”高端养生茶的世界&#xff0c;探…

DORA 机器人中间件学习教程(5)——3D激光雷达数据可视化

DORA中3D激光雷达数据可视化 1 总体思路2 DORA数据接收节点3 编写yml文件4 启动节点参考资料 截止目前 DORA还没有类似于ROS2中RVIZ这样的可视化工具&#xff0c;而在调试算法时我们又需要将数据进行可视化以验证代码的正确性。目前的解决方法是将DORA中的数据发送到ROS2中&…

vscode 远程linux服务器 连接git

vscode 远程linux服务器 连接git 1. git 下载2. git 配置1&#xff09;github 设置2&#xff09;与github建立连接linux端&#xff1a;创建密钥github端&#xff1a;创建ssh key 3. 使用1&#xff09;初始化repository2&#xff09;commit 输入本次提交信息&#xff0c;提交到本…

【Pycharm】显示内存不足the IDE is running low on memory解决方法

Pycharm提示显示内存不足the IDE is running low on memory解决方法 在右上角找到Help&#xff0c;点击&#xff0c;找到change memory settings 修改数值如1024&#xff0c;2048 等&#xff0c;增大容量即可。最后点击save and Restart

【Android】Jetpack入门知识总结(LifeCycle,ViewModel,LiveData,DataBinding等)

文章目录 LifeCycle使用Lifecycle解耦页面与组件自定义控件实现LifecycleObserver接口注册生命周期监听器 使用LifecycleService解耦Service与组件使用ProcessLifecycleOwner监听应用程序生命周期 ViewModel用法在 Fragment 中使用 ViewModel LiveDataDataBinding导入依赖基本用…

2024_E_100_连续字母长度

连续字母长度 题目描述 给定一个字符串&#xff0c;只包含大写字母&#xff0c;求在包含同一字母的子串中&#xff0c;长度第 k 长的子串的长度&#xff0c;相同字母只取最长的那个子串。 输入描述 第一行有一个子串(1<长度<100)&#xff0c;只包含大写字母。 第二行为…

傅里叶分析之掐死教程(完整版)更新于2014.06.06

作 者&#xff1a;韩 昊 知 乎&#xff1a;Heinrich 微 博&#xff1a;花生油工人 知乎专栏&#xff1a;与时间无关的故事 谨以此文献给大连海事大学的吴楠老师&#xff0c;柳晓鸣老师&#xff0c;王新年老师以及张晶泊老师。 转载的同学请保留上面这句话&#xff0c;谢谢。如果…

stable diffusion WEBUI Brief summary

1&#xff0c;rembg(去除背景-》蒙版) import rembg from PIL import Image, ImageOps import numpy as np# 打开图像 input_path "./p_6258838.jpg" input_image Image.open(input_path)# 移除背景&#xff0c;得到带有透明背景的图像 output_image rembg.remove…

IO编程--两进程间的实时通信

一、使用有名管道实现两个进程之间的相互通信 代码如下&#xff1a; 创建有名管道文件 #include <myhead.h> int main(int argc, const char *argv[]) {if(mkfifo("myfifo",0664)-1){perror("create error");return -1;}if(mkfifo("myfifo_1&qu…

UDP/TCP协议详解

目录 一,自定义应用层协议: 1)xml 2),JSON 3),yml 4),google protobuffer 二,传输层UDP/TCP: UDP协议: TCP协议: TCP的核心机制一:确认应答 TCP核心机制二:超时重传 TCP核心机制三:连接管理 TCP核心机制四:滑动窗口 TCP核心机制五:流量控制 TCP核心机制六:拥塞控制…

基于springboot的网上服装购物商城系统

基于springboot的网上服装购物商城系统 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;idea 源码获取&#xff1a; &#x…

Video-LLaMA论文解读和项目部署教程

Video-LLaMA: An Instruction-tuned Audio-Visual Language Model for Video Understanding 相关工作 大型语言模型: 本文的工作基于这些LLM,并提供即插即用插件,使其能够理解视频中的视觉和听觉内容。 多模态大型语言模型: 现有的方法可以分为两大类。 第一类包括使用LL…

【Word原件测试资料合集】软件系统功能测试方案,软件测试方案(整体方案),软件测试文档-测试计划模版(功能与性能),软件测试流程

一、 前言 &#xff08;一&#xff09; 背景 &#xff08;二&#xff09; 目的 &#xff08;三&#xff09; 测试目标 &#xff08;四&#xff09; 适用范围与读者对象 &#xff08;五&#xff09; 术语与缩写 二、 软件测试实施流程 &#xff08;一&#xff09; 测试工作总体流…

stm32驱动W2812

W2812简介 W2812 内置有控制电路和 RGB LED 灯珠&#xff0c;用户只需通过一条数据线进行控制 每一个LED的R、G、B分别由八位数据控制颜色浓度&#xff0c;&#xff08;每种颜色浓度有0~255档&#xff0c;理论上RGB就可以组成256的3次方中颜色组合&#xff09;即每个LED需要…

基于MATLAB的混沌序列图像加密程序

设计目的 图像信息生动形象&#xff0c;它已成为人类表达信息的重要手段之一&#xff0c;网络上的图像数据很多是要求发送方和接受都要进行加密通信&#xff0c;信息的安全与保密显得尤为重要&#xff0c;因此我想运用异或运算将数据进行隐藏&#xff0c;连续使用同一数据对图…