SpringBoot 整合 SpringSecurity

1. 项目目录

在这里插入图片描述

2. pom.xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.6.3</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>2.6.3</version>
</dependency>

3. 创建实体类

LoginForm

package com.cnbai.entity;/*** 登录参数*/
public class LoginForm {private String username;private String password;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

User

package com.cnbai.entity;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;/*** 实现 SpringSecurity 提供的 UserDetails 接口,保存登录信息*/
public class User implements UserDetails {private String username;private String password;/** 用户的权限集,默认需要添加前缀 */@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {ArrayList<SimpleGrantedAuthority> list  = new ArrayList<>();list.add(new SimpleGrantedAuthority("USER"));return list;}/** 用户的加密后的密码,不加密会使用前缀 */@Overridepublic String getPassword() {return password;}/** 应用内唯一的用户名 */@Overridepublic String getUsername() {return username;}/** 账户是否过期 */@Overridepublic boolean isAccountNonExpired() {return true;}/** 账户是否锁定 */@Overridepublic boolean isAccountNonLocked() {return true;}/** 凭证是否过期 */@Overridepublic boolean isCredentialsNonExpired() {return true;}/** 用户是否可用 */@Overridepublic boolean isEnabled() {return true;}
}

4. 创建拦截器

SessionInterceptor

package com.cnbai.intercepter;import com.cnbai.cache.RequestCache;
import com.cnbai.cache.SystemCache;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 自定义拦截器,所有请求之前优先判断 token*/
public class SessionInterceptor implements HandlerInterceptor {/*** 在处理请求之前被调用*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");if (token == null) {return false;}HttpSession session = SystemCache.getSession(token);if (session == null) {return false;}RequestCache.setSession(session);return true;}/*** 在处理请求之后,页面视图渲染之前被调用*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {RequestCache.cleanSession();}/*** 在处理请求完成且页面视图渲染完成后被调用*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("after...");}
}

5. 创建配置类

WebConfig

package com.cnbai.config;import com.cnbai.intercepter.SessionInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 实现 spring 拦截器,自定义拦截范围*/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SessionInterceptor()).addPathPatterns("/**").excludePathPatterns("/login");}
}

SystemConfig

package com.cnbai.config;import com.cnbai.cache.SystemCache;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** Spring容器启动之后,预加载资源,初始化 cache*/
@Configuration
@Order(1)
public class SystemConfig implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {SystemCache.init();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}

DiscoverSecurityConfig

package com.cnbai.config;import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;/*** SpringSecurity 配置类*/
@Configuration
@EnableWebSecurity
public class DiscoverSecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate UserDetailsService userDetailsService;@Resourceprivate PasswordEncoder passwordEncoder;/** 身份认证 */@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);}/** 认证管理 */@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManager();}/** 核心过滤器 */@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/resources/**").antMatchers("/static/**");}/** 安全过滤器链 */@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeHttpRequests().antMatchers("/**").permitAll().anyRequest().authenticated().and().exceptionHandling().accessDeniedPage("/404").and().csrf().disable();}
}

6. 创建缓存

SystemCache

package com.cnbai.cache;import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;/*** 枚举实现单例,维护全局缓存* eq: 缓存 token 和 session 的关系*/
public class SystemCache {/** 初始化 cache */public static void init() {SessionCache.SESSION_CACHE.init();}/** 获取 session */public static HttpSession getSession(String token) {return SessionCache.SESSION_CACHE.getSession(token);}/** 缓存 token 和 session 的关系 */public static void addSession(String token, HttpSession session) {SessionCache.SESSION_CACHE.add(token, session);}/** 清空 session */public static void clearSession(String token) {SessionCache.SESSION_CACHE.clearSession(token);}//====================================================================================private enum SessionCache {SESSION_CACHE;private final Map<String, HttpSession> cache;/** 初始化 cache */private void init() {cache = new HashMap<>(1);}/** 缓存 token 和 session 的关系 */private void add(String token, HttpSession session) {this.cache.put(token, session);}/** 获取 session */private HttpSession getSession(String token) {return this.cache.get(token);}/** 清空 session */private void clearSession(String token) {this.cache.remove(token);}}
}

RequestCache

package com.cnbai.cache;import com.cnbai.entity.User;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.http.HttpSession;/*** 用于存储鉴权用户,session 管理等,此类只维护每一次请求的缓存*/
public class RequestCache {private static final ThreadLocal<HttpSession> THREAD_LOCAL = new ThreadLocal<>();private static final String CURRENT_USER = "user";/** 添加 session 到 ThreadLocal */public static void setSession(HttpSession httpSession) {THREAD_LOCAL.set(httpSession);}/** 获取 session */public static HttpSession getHttpSession() {return THREAD_LOCAL.get();}/** 清空 session */public static void cleanSession() {THREAD_LOCAL.remove();}/** 添加 user 到 session */public static void setUser(User user) {getHttpSession().setAttribute(CURRENT_USER, user);}/** 获取 user */public static User getUser() {Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();if (principal instanceof User) {return (User) principal;} else {return (User) getHttpSession().getAttribute(CURRENT_USER);}}
}

7. 创建 Service

UserServiceImpl

package com.cnbai.service;import com.cnbai.cache.RequestCache;
import com.cnbai.cache.SystemCache;
import com.cnbai.entity.LoginForm;
import com.cnbai.entity.User;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;/*** 用户接口*/
public class UserServiceImpl {@Resourceprivate AuthenticationManager authenticationManager;/*** 登录*/public User login(LoginForm loginForm, HttpServletRequest request) {// 1. 通过 用户名 查询数据库用户信息User userDetail = queryByName(loginForm.getUsername());// 2. 验证密码UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetail, loginForm.getPassword());Authentication authenticate = authenticationManager.authenticate(authenticationToken);SecurityContextHolder.getContext().setAuthentication(authenticate);Object principal = authenticate.getPrincipal();if (principal instanceof User) {User user = (User) principal;RequestCache.setSession(request.getSession());RequestCache.setUser(user);}// 3. 缓存 token 和 session 的关系String token = UUID.randomUUID().toString().replaceAll("-", "");SystemCache.addSession(token, RequestCache.getHttpSession());// 4. 返回结果return RequestCache.getUser();}/*** 注销*/public void logout(HttpServletRequest request) {RequestCache.cleanSession();SecurityContextHolder.clearContext();SystemCache.clearSession(request.getHeader("token"));}
}

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

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

相关文章

基于Datax开发支持瀚高数据库的插件_插件开发_以及部署---国产瀚高数据库工作笔记006

如果想直接使用,开发好的插件,那么可以去下载笔者上传的,打包好的插件,直接放入到 datax安装目录的./datax/plugin/reader 或者writer中就可以了 https://download.csdn.net/download/lidew521/89495306 https://download.csdn.net/download/lidew521/89495301这两个一个…

Unity之创建与导出PDF

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之创建与导出PDF TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff01; 助力快速…

PyPDF2指定范围拆分PDF文件为单个页面

本文目录 前言一、指定范围拆分PDF1、过程讲解2、拆分效果图3、完整代码二、其他问题1、更改页码索引值前言 上一篇文章讲解了怎么讲一个PDF文档分割为多个单页面PDF,本文来讲解一下进阶,就是指定范围拆分PDF页面,有的时候,我们只想把PDF文档中的某几页拆分出来,而不是全…

mmcv安装失败及解决方案

假如想安装的版本是mmcv1.4.0, 但是pip install mmcv1.4.0总是失败&#xff0c;若是直接pip install mmcv会安装成功&#xff0c;但是安装的就是最新版本&#xff0c;后面代码跑起来还会报错&#xff0c;怎么办呢&#xff1f; 接下来分享一个mmcv指定版本安装的方式。 网页&a…

数据存储方案选择:ES、HBase、Redis、MySQL与MongoDB的应用场景分析

一、概述 1.1 背景 在当今数据驱动的时代&#xff0c;选择合适的数据存储技术对于构建高效、可靠的信息系统至关重要。随着数据量的爆炸式增长和处理需求的多样化&#xff0c;市场上涌现出了各种数据存储解决方案&#xff0c;每种技术都有其独特的优势和适用场景。Elasticsear…

【Threejs进阶教程-着色器篇】1. Shader入门(ShadertoyShader和ThreejsShader入门)

ThreejsShader入门 关于本Shader教程认识ShaderShader和Threejs的关系WebGLShaderThreejsShaderShadertoyShader其他Shader 再次劝退数学不好的人从ShaderToy开始Shader的代码是强类型glsl的类型&#xff0c;变量&#xff0c;内置函数&#xff0c;关键字关于uv基于UV的颜色处理…

全网最详细的软件测试面试题总结+基础知识(完整版)

一、什么是软件&#xff1f; 软件是计算机系统中的程序和相关文件或文档的总称。 二、什么是软件测试&#xff1f; 说法一&#xff1a;使用人工或自动的手段来运行或测量软件系统的过程&#xff0c;以检验软件系统是否满足规定的要求&#xff0c;并找出与预期结果之间的差异…

【深海王国】小学生都能玩的语音模块?ASRPRO打造你的第一个智能语音助手(4)

Hi~ (o^^o)♪, 各位深海王国的同志们&#xff0c;早上下午晚上凌晨好呀~ 辛勤工作的你今天也辛苦啦(/≧ω) 今天大都督继续为大家带来系列——小学生都能玩的语音模块&#xff0c;帮你一周内快速学会语音模块的使用方式&#xff0c;打造一个可用于智能家居、物联网领域的语音助…

qtreewidget 美化,htmlcss和qss 不是一个概念!已解决

这种样式的美化&#xff0c; 能气死个人&#xff0c;css 一个单词搞定&#xff0c;非要 在qss中。多少个单词不知道了。 m_tree_widget->setStyleSheet("QTreeView{background:transparent; selection-background-color:transparent;}""QTreeView::branch{b…

linux 安装腾讯会议和解决ubuntu打开腾讯会议提示:不兼容 wayland 协议

一. 下载腾讯会议安装包 腾讯会议下载链接 二. 命令行安装 cd [安装包路径] sudo dpkg -i TencentMeeting_0300000000_3.19.1.400_x86_64_default.publish.deb 三. 打开腾讯会议提示无法支持wayland 协议 解决方法: 打开终端 sudo vi /etc/gdm3/custom.conf打开 #Wayland…

哪个牌子的充电宝牌子便宜好用?2024年性价比高充电宝排行榜!

在 2024 年&#xff0c;充电宝市场依旧琳琅满目&#xff0c;让人眼花缭乱。大家都在寻找那个既便宜又好用的充电宝&#xff0c;可面对众多品牌和产品&#xff0c;常常感到无从下手。别担心&#xff01;经过深入的市场调研和实际使用体验&#xff0c;我们为您精心整理出了 2024 …

轻度图像处理工具,匹敌photoshop

一、简介 1、一款功能强大的在线图片编辑工具,用户可以将其安装为渐进式网页应用(PWA)。它提供了与 Photoshop 相似的核心功能,能够满足大多数图像编辑需求,非常适合那些不愿或无法安装 Photoshop 的用户。即使使用免费版本,用户也能享受所有功能,是轻度图像处理的理想选…

实用麦克风话筒音频放大器电路设计和电路图

设计目标 输入电压最大值输出电压最大值电源Vcc电源Vee频率响应偏差20Hz频率响应偏差20kHz100dB SPL(2Pa)1.228Vrms5V0V–0.5dB–0.1dB 设计说明 此电路使用跨阻抗放大器配置中的运算放大器将驻极体炭精盒麦克风的输出电流转换为输出电压。此电路的共模电压是固定的&#xf…

动物检测yolo格式数据集(水牛 、大象 、犀牛 、斑马四类)

动物检测数据集 1、下载地址&#xff1a; https://download.csdn.net/download/qq_15060477/89512588?spm1001.2101.3001.9500 2、数据集介绍 本数据集含有四种动物可以检测&#xff0c;分别是水牛 、大象 、犀牛 、斑马四类&#xff0c;数据集格式为yolo格式&#xff0c;…

大模型对汽车行业意味着什么?_汽车企业大模型

引 言 大模型是一种利用海量数据进行训练的深度神经网络模型&#xff0c;其特点是拥有庞大的参数规模和复杂的计算结构。通过在大规模数据集上进行训练&#xff0c;大模型能够学习到丰富的模式和特征&#xff0c;从而具备强大的泛化能力&#xff0c;可以对未知数据做出准确的预…

Vue87-Vuex中的mapState、mapGetters

一、借助mapState生成计算属性&#xff0c;从state中读取数据 当vuex中的state有很多数据的时候&#xff1a; 组件中调用state中的数据 此写法不是很方便&#xff0c;借助计算属性。 计算属性的写法也不是很方便&#xff1a; 优化&#xff1a; 1-1、对象写法 注意&#xff1a…

JVM原理(十二):JVM虚拟机类加载过程

一个类型从被加载到虚拟机内存中开始&#xff0c;到卸载为止&#xff0c;它的整个生命周期将会经过 加载、验证、准备、解析、初始化、使用、卸载七个阶段。其中 验证、准备、解析三个部分统称为 连接 1. 加载 加载是整个类加载的一个过程。在加载阶段&#xff0c;Java虚拟机…

使用python编程的视频文件列表应用程序

简介&#xff1a; 在本篇博客中&#xff0c;我们将介绍一个基于 wxPython 的视频文件列表应用程序。该应用程序允许用户选择一个文件夹&#xff0c;并显示该文件夹中的视频文件列表。用户可以选择文件并查看其详细信息&#xff0c;导出文件列表为文本文件&#xff0c;以及播放…

Spring系统学习-什么是AOP?为啥使用AOP?

问题思考 我们为啥要使用AOP? 来看一个案例&#xff1a; 声明计算器接口Calculator&#xff0c;包含加减乘除的抽象方法 public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j); }public class Calculat…

JS(JavaScript)数据校验 表单校验-案例

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…