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.hqwc.cn/news/235971.html

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

相关文章

【经验分享】openGauss 客户端(Data Studio / DBeaver)连接方式

前言 本篇介绍了openGauss常用的客户端连接工具Data Studio和DBeaver 01 客户端工具 openGauss部署之后&#xff0c;在服务器上提供了在命令行下运行的数据库连接工具gsql。此工具除了具备操作数据库的基本功能&#xff0c;还提供了若干高级特性&#xff0c;便于用户使用。…

【Node.js】笔记整理 5 - Express框架

写在最前&#xff1a;跟着视频学习只是为了在新手期快速入门。想要学习全面、进阶的知识&#xff0c;需要格外注重实战和官方技术文档&#xff0c;文档建议作为手册使用 系列文章 【Node.js】笔记整理 1 - 基础知识【Node.js】笔记整理 2 - 常用模块【Node.js】笔记整理 3 - n…

qt5.15播放音频示例(4种方法)

文章目录 Qt播放音频方法一 QMediaPlayer方法二 QSound方法三 QSoundEffect方法四 QAudioOutput问题1 播放无声问题2 QAudioOutput播放嗡嗡声的问题参考Qt播放音频 在linux系统中,可以通过aplay进行简单的播放音频,如 aplay /opt/Audio/test.wav在图形界面,也可以封装apla…

玩转大数据:3-Hadoop家族的力量与挑战

引言 Hadoop作为一个强大的大数据处理框架&#xff0c;以其分布式计算和存储能力在业界备受关注。然而&#xff0c;Hadoop在应用场景、适用范围、社区支持以及后续持续发展等方面也面临着一些挑战。本文将围绕Hadoop的生态应用&#xff0c;以及来自其他生态的挑战&#xff0c;…

【排序,直接插入排序 折半插入排序 希尔插入排序】

文章目录 排序排序方法的分类插入排序直接插入排序折半插入排序希尔插入排序 排序 将一组杂乱无章的数据按照一定规律排列起来。将无序序列排成一个有序序列。 排序方法的分类 储存介质&#xff1a; 内部排序&#xff1a;数据量不大&#xff0c;数据在内存&#xff0c;无需…

leetcode 18. 四数之和(优质解法)

代码&#xff1a; class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {List<List<Integer>> listsnew ArrayList<>();int lengthnums.length;Arrays.sort(nums);for(int i0;i<length-4;){for(int ji1;j<lengt…

【ArcGIS Pro二次开发】:CC工具箱1.1.4更新_免费_50+工具

CC工具箱1.1.4更新【2023.11.30】 使用环境要求&#xff1a;ArcGIS Pro 3.0 一、下载链接 工具安装文件及使用文档&#xff1a; https://pan.baidu.com/s/1OJmO6IPtMfX_vob3bMtvEg?pwduh5rhttps://pan.baidu.com/s/1OJmO6IPtMfX_vob3bMtvEg?pwduh5r 二、使用方法 1、在下…

抖音本地生活服务商申请条件

抖音的本地生活服务商目前有两种&#xff0c;一种是可以做全国的服务商&#xff0c;我们一般叫抖音本地生活服务商&#xff0c;一种是区域优待服务商&#xff0c;也就是后面出来的服务商&#xff0c;这两种服务商的申请方式大同小异。 相同的地方就是都需要给平台交保证金。抖…

Go语言 值传递

官方说法&#xff0c;Go中只有值传递&#xff0c;没有引用传递 而Go语言中的一些让你觉得它是引用传递的原因&#xff0c;是因为Go语言有值类型和引用类型&#xff0c;但是它们都是值传递。 值类型 有int、float、bool、string、array、sturct等 引用类型有slice&#xff0c…

FlatLaf:干净、优雅、扁平化,基于java swing现代开源跨平台外观

一个很不错的java swing ui库&#xff0c;idea主题风格&#xff0c;还能自定义 FlatLaf是用于JavaSwing 桌面应用程序的现代开源跨平台外观。 它看起来几乎是平的&#xff08;没有阴影或渐变&#xff09;、干净、简单和优雅。FlatLaf带有Light、Dark、IntelliJ和Darcula主题&a…

11 款顶级的免费 iPhone 数据恢复软件

iPhone 拥有巨大的存储容量。您可以在 iPhone 设备上存储图像、文档和视频等数据。有时&#xff0c;您的 iPhone 会发生许多意外事件&#xff0c;例如意外删除&#xff0c;从而导致数据丢失。这里有 11 个最好的免费 iPhone 数据恢复软件&#xff0c;您可以免费下载&#xff0c…

[架构之路-255]:目标系统 - 设计方法 - 软件工程 - 软件设计 - 架构设计 - 软件架构风格

前言&#xff1a; 风格是指在不同领域内&#xff0c;人们在表达自己的过程中&#xff08;如艺术、音乐、文化、时尚、建筑、软件系统等&#xff09;&#xff0c;所选择的、相对稳定的表达方式和特征的总和。在不同领域内都存在着多种不同的风格。 在艺术领域内&#xff0c;也…