Spring Security 的使用

一、简介 

1.1、Spring Security 相关概念

1.过滤器链(Filter Chain)
基于Servlet过滤器(Filter)处理和拦截请求,进行身份验证、授权等安全操作。过滤器链按顺序执行,每个过滤器负责一个具体的安全功能。

2.SecurityInterceptor(安全拦截器)
根据配置的安全规则拦截请求,进行访问控制和权限验证。

3.Authentication(认证对象)
封装用户的认证信息(账户状态、用户名、密码、权限等)
Authentication常用实现类:
    UsernamePasswordAuthenticationToken:用户名密码登录的 Token
    AnonymousAuthenticationToken:针对匿名用户的 Token
    RememberMeAuthenticationToken:记住我功能的的 Token

4.AuthenticationManager (用户认证的管理类)
所有的认证请求都会封装成一个Token 给 AuthenticationManager,AuthenticationManager 调用 AuthenticationProvider.authenticate() 认证,返回包含认证信息的 Authentication 对象。

5.AuthenticationProvider(认证的具体实现类)
一个 provider 是一种认证方式实现,主流的认证方式都已经提供了默认实现,如 DAO、LDAP、CAS、OAuth2等。

6.UserDetailService(用户详细信息服务)
通过 UserDetailService 拿到数据库(或内存)中的认证信息然后和客户端提交的认证信息做校验。

7.访问决策管理器(AccessDecisionManager)
在授权过程中进行访问决策。根据用户的认证信息、请求的URL和配置的权限规则,判断用户是否有权访问资源。

8.SecurityContext(安全上下文)
认证通过后,会为这用户生成一个唯一的 SecurityContext(ThreadLocal存储),包认证信息 Authentication。
通过 SecurityContext 可获取到用户的标识 Principle 和授权信息 GrantedAuthrity。
系统任何地方只要通过 SecurityHolder.getSecruityContext() 可获取到 SecurityContext。

9.注解和表达式支持 
用在代码中声明和管理安全规则。如@Secured注解可以标记在Controller或方法上,限制权限用户才能访问。

1.2、核心的过滤器链 

1.SecurityContextPersistenceFilter 
Filter的入口和出口,将 SecurityContext (登录后的信息)对象持久到Session,同时把 SecurityContext 设置给 SecurityContextHolder 获取用户认证授权信息。

2.UsernamePasswordAuthenticationFilter 
默认拦截“/login”登录请求,处理表单提交的登录认证,将请求中的认证信息封装成 UsernamePasswordAuthenticationToken,然后调 AuthenticationManager 进行认证。

3.BasicAuthenticationFilter 
基本认证,支持 httpBasic 认证方式的Filter。

4.RememberAuthenticationFilter 
记住我功能实现的 Filter。

5.AnonymousAuthenticationFilter 
处理匿名访问的资源,如果用户未登录,会创建匿名的Token(AnonymousAuthenticationToken),通过 SecurityContextHodler 设置到 SecurityContext 中。

6.ExceptionTranslationFilter 
捕获 FilterChain 所有的异常,但只处理 AuthenticationException、AccessDeniedException 异常,其他的异常会继续抛出。

7.FilterSecurityInterceptor 
做授权的Filter,通过父类(AbstractSecurityInterceptor.beforeInvocation)调用 AccessDecisionManager.decide 方法对用户授权。

1.3、Spring Security 使用场景 

1.用户登录和认证
可处理用户的身份验证。如表单登录、基本认证、OAuth等。
2.授权和权限管理
可定义安全规则和访问控制,可用注解、表达式或配置文件来声明和管理权限,确保用户只能访问其有权访问的资源。
3.防止跨站点请求伪造(CSRF)
可生成和验证CSRF令牌,防止Web应用程序受到CSRF攻击。可在表单中自动添加CSRF令牌,并验证提交请求中的令牌值。
4.方法级安全性
允许在方法级别对方法进行安全性配置。可用注解或表达式来定义哪些用户有权调用特定方法。
5.记住我功能
允许用户在下次访问时保持登录状态,不要重新输入用户名和密码。
6.单点登录(SSO)
可与其他身份验证和授权提供程序集成,实现单点登录。
7.安全事件和审计日志
可记录安全事件和用户操作,以便进行审计和故障排查。

二、SpringBoot 中基本使用 

2.1、引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId>
</dependency>

2.2、外围的配置

2.2.1、登录页面static/login.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登陆</title>
</head>
<body>
<h1>登陆</h1>
<form method="post" action="/login"><div class="checkbox"><label><input type="checkbox" id="rememberme" name="remember-me"/>记住我</label></div><div>用户名:<input type="text" name="username"></div><div>密码:<input type="password" name="password"></div><div><button type="submit">立即登陆</button></div>
</form>
</body>
</html>

2.2.2、启动类、访问接口

@SpringBootApplication
public class ApplicationConfig {public static void main(String[] args) {SpringApplication.run(ApplicationConfig.class);}
}@Controller
public class AuthController {//登录成功后重定向地址@RequestMapping("/loginSuccess")@ResponseBodypublic String loginSuccess(){return "登录成功";}
}

2.2.3、DDL、实体类、Dao层接口

    SET FOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for t_permission 权限-- ----------------------------DROP TABLE IF EXISTS `t_permission`;CREATE TABLE `t_permission` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`resource` varchar(255) NOT NULL,`state` int(11) DEFAULT NULL,`menu_id` bigint(20) DEFAULT NULL,`expression` varchar(255) NOT NULL,PRIMARY KEY (`id`),KEY `menu_id` (`menu_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ------------------------------ Table structure for t_role 角色-- ----------------------------DROP TABLE IF EXISTS `t_role`;CREATE TABLE `t_role` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`sn` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ------------------------------ Table structure for t_role_permission 角色和权限关系-- ----------------------------DROP TABLE IF EXISTS `t_role_permission`;CREATE TABLE `t_role_permission` (`role_id` bigint(20) NOT NULL,`permission_id` bigint(20) NOT NULL,PRIMARY KEY (`role_id`,`permission_id`),KEY `permission_id` (`permission_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ------------------------------ Table structure for t_login 用户登录表-- ----------------------------DROP TABLE IF EXISTS `t_login`;CREATE TABLE `t_login` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`username` varchar(255) DEFAULT NULL COMMENT '员工用户名',`password` varchar(255) DEFAULT NULL COMMENT '密码',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ------------------------------ Table structure for t_login_role 用户角色关系表-- ----------------------------DROP TABLE IF EXISTS `t_login_role`;CREATE TABLE `t_login_role` (`login_id` bigint(20) NOT NULL,`role_id` bigint(20) NOT NULL,PRIMARY KEY (`login_id`,`role_id`),KEY `role_id` (`role_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ------------------------------ Table structure for persistent_logins 用户登录记住表-- ----------------------------CREATE TABLE `persistent_logins` (`username` varchar(64) NOT NULL DEFAULT '',`series` varchar(64) NOT NULL,`token` varchar(64) NOT NULL,`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`series`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
	
public class Login {private Long id;private String username;private String password;
}public class Permission {private Long id;private String name;private String sn;private String resource;
}import cn.itsource.security.domain.Login;
import cn.itsource.security.domain.Permission;
import java.util.List;public interface LoginMapper {Login selectByUsername(String username);
}import cn.itsource.security.domain.Permission;
import java.util.List;public interface PermissionMapper {List<Permission> selectPermissionsByUserId(Long userId);List<Permission> selectAll();
}

2.2.4、数据库连接、数据插入

略 . . . . . . 

2.3、配置类 WebSecurityConfigurerAdapter 

配置类 WebSecurityConfigurerAdapter
创建UserDetailService的Bean,用来加载用户认证信息。
配置编码器,通过该编码器对密码进行加密匹配。
授权规则配置,哪些资源需要什么权限。@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate DataSource dataSource ;/**//提供用户信息,这里没有从数据库查询用户信息,在内存中模拟@Beanpublic UserDetailsService userDetailsService(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("JunSouth").password("123").authorities("admin").build());return inMemoryUserDetailsManager;}*/@Beanpublic PersistentTokenRepository persistentTokenRepository(){JdbcTokenRepositoryImpl obj = new JdbcTokenRepositoryImpl();obj.setDataSource(dataSource);//obj.setCreateTableOnStartup(false);	//启动创建表persistent_logs表,存token,username时会用到return obj;}@Beanpublic PasswordEncoder passwordEncoder(){//return new BCryptPasswordEncoder();//密码编码器:不加密return NoOpPasswordEncoder.getInstance();}//授权规则配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/login").permitAll()  //登录路径放行.antMatchers("/login.html").permitAll() //对登录页面跳转路径放行.anyRequest().authenticated() //其他路径都要拦截.and().formLogin()  //允许表单登录, 设置登陆页.successForwardUrl("/loginSuccess") // 设置登陆成功页.loginPage("/login.html")   //登录页面跳转地址.loginProcessingUrl("/login")   //登录处理地址(必须).and().logout().logoutUrl("/mylogout").permitAll()    //制定义登出路径.logoutSuccessHandler(new MyLogoutHandler())  //登出后处理器-可以做一些额外的事情.invalidateHttpSession(true); //登出后session无效http.rememberMe().tokenRepository(persistentTokenRepository())	//持久.tokenValiditySeconds(3600)	//过期时间.userDetailsService(userDetailsService); //用来加载用户认证信息的}
}

2.4、 定义 UserDetailsService 

/*** 提供给 security 的用户信息的 service,要复写 loadUserByUsername 方法返回数据库中的用户信息*/
@Service
public class UserDetailServiceImpl implements UserDetailsService {@Autowareprivate LoginMapper loginMapper;/*** 加载数据库中的认证的用户的信息:用户名、密码、用户的权限列表* 通过username查询用户的信息,(密码,权限列表等)封装成 UserDetails 返回,交给 security 。*/@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {		Login userFromMysql = loginMapper.selectByUsername(username);if(loginFromMysql == null){throw new UsernameNotFoundException("无效的用户名");}//前台用户List<GrantedAuthority> permissions = new ArrayList<>();List<Permission> permissionSnList = systemManageClient.listByUserId(loginFromMysql.getId());permissionSnList.forEach(permission->{System.out.println("用户:"+username+" :加载权限 :"+permission.getSn());permissions.add(new SimpleGrantedAuthority(permission.getSn()));});//密码是基于BCryptPasswordEncoder加密的密文,User是security内部的对象,UserDetails的实现类 ,//用来封装用户的基本信息(用户名,密码,权限列表),四个 true 分别是账户启用、账户过期、密码过期、账户锁定return new User(username,loginFromMysql.getPassword(),true,true,true,true,permissions);}
}

2.5、认证结果处理

/*** 认证——成功处理*/
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");Map map = new HashMap<>();map.put("success",true);map.put("message","认证成功");map.put("data",authentication);response.getWriter().print(JSON.toJSONString(map));response.getWriter().flush();response.getWriter().close();}
}/*** 认证——失败处理*/
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");Map map = new HashMap<>();map.put("success",false);map.put("message","认证失败");response.setStatus(HttpStatus.UNAUTHORIZED.value());response.getWriter().print(JSON.toJSONString(map));response.getWriter().flush();response.getWriter().close();}
}

2.6、授权结果处理

/*** 授权失败——定义认证检查失败处理*/
public class DefaultAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {String result = JSON.toJSONString(AjaxResult.me().setSuccess(false).setMessage("无访问权限"));response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.print(result);writer.flush();writer.close();}
}/*** 授权失败——定义匿名用户访问无权处理*/
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {e.printStackTrace();httpServletResponse.setContentType("application/json;charset=utf-8");Map<String,Object> result = new HashMap<>();result.put("success",false);result.put("message","登录失败,用户名或密码错误["+e.getMessage()+"]");httpServletResponse.getWriter().print(JSONUtils.toJSONString(result));}
}

2.7、登出处理 

/*** 登出处理器*/
public class MyLogoutHandler implements LogoutHandler {@Overridepublic void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {try {//登出成功,响应结果给客户端,通常是一个JSON数据response.getWriter().println("logout success");} catch (IOException e) {e.printStackTrace();}}
}

2.8、操作—注册、登录 

http://localhost:8080/login,
进入登录页面,输入账号:JunSouth 密码 123 完成登录

public class PasswordTest {@Testpublic void testPassword(){BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();String enPass = bCryptPasswordEncoder.encode("123");System.out.println(enPass);System.out.println(bCryptPasswordEncoder.matches("123", enPass));}
}

2.9、操作—获取用户信息 

2.10、白名单、资源定制访问、不同级别访问

三、关键且重要的

3.1、角色

3.2、加密

3.3、权限定制与绑定

四、登陆方式

4.2、单点登录(手机、微信、支付宝)

4.3、用户名登陆

4.4、其它定制登录

五、注意事项

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

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

相关文章

入门Python+Vue 全栈开发可视化BI数据项目几个要点总结

随着数据的快速增长和业务的复杂性&#xff0c;越来越多的企业开始关注数据分析和可视化。在本文中&#xff0c;我们将介绍如何使用Python和Vue进行全栈开发&#xff0c;构建一个可视化BI数据项目&#xff0c;并总结几个关键要点。 首先&#xff0c;Python是一种强大而灵活的编…

利用Linux中的iptables进行网络代理配置

作为资深爬虫技术员&#xff0c;爬虫需要代理IP池介入这是众所周知的。今天我将用我毕生所学&#xff0c;谈谈linux中使用iptables工具来进行网络配置&#xff0c;并通过linux系统创建属于自己的ip库池&#xff0c;如有错误望各位大佬指正。 我们知道&#xff0c;在Linux中&am…

java-Swing界面简析

一、简析&#xff1a; 调用java提供的 java.swing包下的各种类可以实现界面中的各种组件(比如输入框、密码框按钮、单选框、复选框等) 二、java.swing包的关键类&#xff1a; 顶层容器&#xff1a;Jframe(窗口) 中间容器&#xff1a;Jpanel(面板) 基本控件&#xff1a; I…

FL Studio水果软件最新21.1.1.3750破解版下载

FL Studio是一款流行的图像线软件制作和编辑音频文件。作为一款领先的创新产品&#xff0c;该软件能够满足在创作音乐方面的需求。有了这个产品&#xff0c;可以完成制作音乐的整个过程。可以使用这个软件进行写作&#xff0c;编辑&#xff0c;录音&#xff0c;编辑和混合和掌握…

【服务部署】常用内网穿透方案

一、前言 由于一些开发及使用需求&#xff0c;需要将内网机器端口映射到公网&#xff0c;达到公网访问内网环境的目的 本文主要介绍几种常用的内网穿透方案 ssh远程端口转发 部署简单&#xff0c;无需额外安装软件包 frp反向代理 功能配置丰富&#xff0c;部署相对复杂&#…

uni-app 自带返回方法onBackPress,返回上一级并且刷新页面内容获取最新的数据

onBackPress 返回上一级并且刷新页面内容获取最新的数据 onBackPress 方法是uinapp自带返回键方法&#xff0c;也就是在app和H5返回键 onBackPress() {setTimeout(() > {uni.switchTab({url: /pages/Users/index,})}, 300)return true}, methods: {}在这里 uni.switchTab…

Linux 命令pwd

命令作用 pwd是Linux中一个非常有用而又十分简单的命令&#xff0c;pwd是词组print working directory的首字母缩写&#xff0c;即打印工作目录&#xff1b;工作目录就是你当前所处于的那个目录。 pwd始终以绝对路径的方式打印工作目录&#xff0c;即从根目录&#xff08;/&am…

LeetCode(45)最长连续序列【哈希表】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 最长连续序列 1.题目 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&a…

7.23 SpringBoot项目实战【评论】

文章目录 前言一、编写控制器二、编写服务层三、Postman测试前言 我们在 7.4 和 7.20 都曾实现过 评论列表,本文我们继续SpringBoot项目实战 评论 功能。逻辑实际相当Easy:一个学生 对 任意书 都可以 多次评论,但需要经过审核! 回顾一下 4.2 的数据库设计,学生图书评论表…

vue3+element-plus+vue-cropper实现裁剪图片上传

1.vue3element-plusvue-cropper实现裁剪图片 element-UI官网element-plus官网vue-croppervue3使用vue-cropper安装&#xff1a;npm install vue-croppernext 2.vue-cropper插件&#xff1a; <vue-cropper :img"option.img" /><script setup>import {reac…

STM32F407-14.3.7-01PWM输入模式

PWM 输入模式 此模式是输入捕获模式的一个特例。其实现步骤与输入捕获模式基本相同&#xff0c;仅存在以下不同之处&#xff1a; 例如&#xff0c;可通过以下步骤对应用于 TI1① 的 PWM 的周期&#xff08;位于 TIMx_CCR1⑨ 寄存器中&#xff09;和占空 比&#xff08;位于 …

认识JVM 一个Java文件的JVM之旅

准备 我是一个java文件&#xff0c;如何实现我的功能呢&#xff1f;需要去JVM(Java Virtual Machine)这个地方旅行。 变身 我高高兴兴的来到JVM&#xff0c;想要开始JVM之旅&#xff0c;它确说&#xff1a;“现在的我还不能进去&#xff0c;需要做一次转换&#xff0c;生成c…

VUE2+THREE.JS 模型上方显示信息框/标签(CSS3DSprite精灵模型)

THREE.JS 模型上方显示信息框/标签---CSS3DSprite精灵模型 1.CSS2DRenderer/CSS3DRenderer/Sprite的优劣2.实现模型上方显示信息框2.1 引入2.2 初始化加载的时候就执行此方法2.3 animate循环执行2.4 获取设备状态并在每个设备上显示设备状态2.5 样式 CSS3DSprite精灵模型面向摄…

python中的函数定义

默认参数 注&#xff1a; 在Python中&#xff0c;print(x, and y both correct)是一条打印语句&#xff08;print statement&#xff09;&#xff0c;用于将一条消息输出到控制台或终端。它的作用是将变量x的值和字符串and y both correct同时输出到屏幕上。 在这个语句中&…

Windows11如何让桌面图标的箭头消失(去掉快捷键箭头)

在Windows 11中&#xff0c;桌面图标的箭头是快捷方式图标的一个标志&#xff0c;用来表示该图标是一个指向文件、文件夹或程序的快捷方式。如果要隐藏这些箭头&#xff0c;你需要修改Windows注册表或使用第三方软件。 在此之前&#xff0c;我需要提醒你&#xff0c;修改注册表…

Android 滑动按钮(开关) SwitchCompat 自定义风格

原生的SwitchCompat控件如下图&#xff0c;不说不堪入目&#xff0c;也算是不敢恭维了。开个玩笑... 所以我们就需要对SwitchCompat进行自定义风格&#xff0c;效果如下图 代码如下 <androidx.appcompat.widget.SwitchCompatandroid:id"id/switch_compat"android:…

【Linux】第二十二站:文件(二)深入理解重定向

文章目录 一、重定向1.文件描述符对应的分配规则2.重定向的接口 二、再次实现myshell1.实现细节2.盘点文件与进程替换的一个细节3.代码 三、1号文件和2号文件的区别四、如何理解“一切皆文件&#xff1f;” 一、重定向 1.文件描述符对应的分配规则 我们先看如下代码 #includ…

《C++PrimerPlus》第9章 内存模型和名称空间

9.1 单独编译 Visual Studio中新建头文件和源代码 通过解决方案资源管理器&#xff0c;如图所示&#xff1a; 分成三部分的程序&#xff08;直角坐标转换为极坐标&#xff09; 头文件coordin.h #ifndef __COORDIN_H__ // 如果没有被定义过 #define __COORDIN_H__struct pola…

智能优化算法应用:基于平衡优化器算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于平衡优化器算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于平衡优化器算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.平衡优化器算法4.实验参数设定5.算法结果…

全志XR806基于FreeRTOS下部署竞技机器人先进模糊控制器

前言 很荣幸参与到由“极术社区和全志在线联合组织”举办的XR806开发板试用活动。本人热衷于各种的开发板的开发&#xff0c;同时更愿意将其实现到具体项目中。秉承以上原则&#xff0c;发现大家的重心都放在开发中的环境构建过程&#xff0c;缺少了不少实际应用场景的运用&am…