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,一经查实,立即删除!

相关文章

【CSS】深入浅出弹性布局

CSS的弹性布局&#xff08;Flexbox&#xff09;是一种用于在容器中沿着一维方向&#xff08;水平或垂直&#xff09;来布局、对齐和分配容器内项目空间的有效方式。它旨在提供一个更加有效的方式来布局、对齐和分配容器中项目的空间&#xff0c;即使它们的大小未知或是动态变化…

【手撕面试题】React(高频知识点一)

每天10道题&#xff0c;100天后&#xff0c;搞定所有前端面试的高频知识点&#xff0c;加油&#xff01;&#xff01;&#xff01;在看文章的同时&#xff0c;希望不要直接看答案&#xff0c;先思考一下自己会不会&#xff0c;如果会&#xff0c;自己的答案是什么&#xff1f;想…

XFeat快速图像特征匹配算法

XFeat&#xff08;Accelerated Features&#xff09;是一种新颖的卷积神经网络&#xff08;CNN&#xff09;架构&#xff0c;专为快速和鲁棒的像匹配而设计。它特别适用于资源受限的设备&#xff0c;同时提供了与现有深度学习方法相比的高速度和准确性。 轻量级CNN架构&#xf…

基于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; 助力快速…

SQLMap工具详解与SQL注入防范

SQLMap工具详解与SQL注入防范 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨SQLMap工具的详细使用方法以及如何防范SQL注入攻击。 SQL注入简介 SQL注入是一种常见的安全漏洞&am…

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…

计算属性和侦听属性有什么区别?

在 Vue.js 中&#xff0c;计算属性&#xff08;computed properties&#xff09;和侦听属性&#xff08;watcher&#xff09;是两种处理数据变化的方式&#xff0c;它们都允许开发者根据数据的变化来更新组件的状态。虽然它们的目标类似&#xff0c;但它们的工作方式和使用场景…

【Linux】性能分析器 perf 详解(四):trace

上一篇:【Linux】性能分析器 perf 详解(三) 1、trace 1.1 简介 perf trace 类似于 strace 工具:用于对Linux系统性能分析和调试的工具。 原理是:基于 Linux 性能计数器(Performance Counters for Linux, PCL),监控和记录系统调用和其他系统事件。 可以提供关于硬件…

数据存储方案选择: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;并找出与预期结果之间的差异…

Android 解决 “Module was compiled with an incompatible version of Kotlin“ 问题

解决 “Module was compiled with an incompatible version of Kotlin” 问题 在Android开发中&#xff0c;有时我们会遇到Kotlin版本不兼容的问题。具体来说&#xff0c;你可能会看到如下错误&#xff1a; D:/.gradle/caches/transforms-3/caf5371a15e0d6ffc362b4a5ece9cd49…

【深海王国】小学生都能玩的语音模块?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 的用户。即使使用免费版本,用户也能享受所有功能,是轻度图像处理的理想选…