Spring Security
创始人
2024-11-19 07:07:50
0

Spring Security

它是Spring家族中的一个安全管理框架,具备功能有:身份认证、授权、防御常见攻击(CSRF、HTTP Headers、HTTP Requests),它的底层原理是传统的Servlet过滤器

官方文档:

https://docs.spring.io/spring-security/reference/index.html

spring-security官方案例:

https://github.com/spring-projects/spring-security-samples/tree/main)

自定义配置

基于内存的用户认证

UserDetailsService用来管理用户信息

@Configuration @EnableWebSecurity //Spring项目总需要添加此注解 public class WebSecurityConfig {     @Bean     public UserDetailsService userDetailsService() {         InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();         manager.createUser(              User             .withDefaultPasswordEncoder()             .username("yan")     //自定义用户名             .password("123456")  //自定义密码             .roles("USER")       //自定义角色             .build()         );         return manager;     } } 

再次登录页面,必须输入所设置的用户名和密码,才可以登录成功,否则失败,不再使用Security默认的用户名和密码。

基于数据库的数据源

基础sql脚本

-- 创建数据库 CREATE DATABASE `security-demo`; USE `security-demo`;  -- 创建用户表 CREATE TABLE `user`( 	`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键', 	`username` VARCHAR(50) DEFAULT NULL COMMENT '用户名', 	`password` VARCHAR(500) DEFAULT NULL COMMENT '密码', 	`enabled` BOOLEAN NOT NULL COMMENT '是否启动' ); -- 唯一索引 CREATE UNIQUE INDEX `user_username_uindex` ON `user`(`username`);   -- 插入用户(密码是 "abc" ) INSERT INTO `user` (`username`, `password`, `enabled`) VALUES ('admin', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE), ('Helen', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE), ('Tom', '{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW', TRUE); 

完成基础的增删改查…

@Configuration public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {      @Resource     private UserMapper userMapper;  // 数据库 - 用户表mapper          @Override     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {         // sql - 查询用户表 (根据用户名,进行查询用户表)         User user = userMapper.selectOne(username);         if (user == null) {             throw new UsernameNotFoundException(username);         } else {             Collection authorities = new ArrayList<>();             return new org.springframework.security.core.userdetails.User(                     user.getUsername(),                     user.getPassword(),                     user.getEnabled(),                     true,        // 用户账号是否过期                     true,        // 用户凭证是否过期                     true,        // 用户是否未被锁定                     authorities);// 权限列表         }     }      @Override     public UserDetails updatePassword(UserDetails user, String newPassword) {         return null;     }      // 创建用户     @Override     public void createUser(UserDetails userDetails) {         User user = new User();         user.setUsername(userDetails.getUsername());         user.setPassword(userDetails.getPassword());         user.setEnabled(true);         userMapper.insert(user);     }      @Override     public void updateUser(UserDetails user) {      }      @Override     public void deleteUser(String username) {      }      @Override     public void changePassword(String oldPassword, String newPassword) {      }      @Override     public boolean userExists(String username) {         return false;     }  } 

加密算法

Hash算法:

Spring Security的PasswordEncoder接口用于对密码进行单向转换,使用哈希算法,例如MD5、SHA-256、SHA-512等,哈希算法是单向的,只能加密,不能解密。缺点:通过破解的方式猜测密码。

彩虹表:

恶意用户创建称为彩虹表的查找表,越是复杂的密码,需要的彩虹表就越大。

加盐密码:

盐是随机生产的字节(是明文的),盐和用户的密码一起经过哈希函数运算,生产一个哈希值,再与库的密码进行比较,可避免彩虹表,每个盐和密码它的哈希值都是不同的。

自适应单向函数:

随着硬件的不断发展,加盐哈希也不再安全。因为计算机可以每秒执行亿级别哈希运行,所有自适应单向函数,产生一个工作因子,来故意占用CPU、内存,让攻击者很难破解。

PasswordEncoder

  • BCryptPasswordEncoder:使用广泛支持的bcrypt算法来对密码进行哈希。为了增加对密码破解的抵抗力,bcrypt故意设计得较慢。和其他自适应单向函数一样,应该调整其参数,使其在您的系统上验证一个密码大约需要1秒的时间。
  • Argon2PasswordEncoder:使用Argon2算法对密码进行哈希处理。Argon2是密码哈希比赛的获胜者。
  • Pbkdf2PasswordEncoder:使用PBKDF2算法对密码进行哈希处理。为了防止密码破解,PBKDF2是一种故意缓慢的算法。
  • SCryptPasswordEncoder:使用scrypt算法对密码进行哈希处理。为了防止在自定义硬件上进行密码破解,scrypt是一种故意缓慢的算法

自定义登录页

创建对应的html的登录页,在Security自定义配置类里,添加:

@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {     http.authorizeRequests(a -> {             a.anyRequest()      // 对所有请求开启授权保护              .authenticated();  // 已认证的请求会自动授权         })         .formLogin(f -> {             f.loginPage("/login").permitAll() // 登录页面无需授权即可访问              .usernameParameter("username")   // 自定义表单用户名参数,默认是username              .passwordParameter("password")   // 自定义表单密码参数,默认是password              .failureUrl("/login?error");     //登录失败的返回地址         }); // 表单授权方式     http.csrf(csrf -> csrf.disable());  // 暂时关闭csrf攻击     return http.build(); } 

前后端分离

用户认证

  • 登录成功后调用:AuthenticationSuccessHandler
  • 登录失败后调用:AuthenticationFailureHandler

需要重写这2个过滤器,然后在Security自定义配置类进行对应的配置。

注销处理

  • 注销处理调用:LogoutSuccessHandler

需要重写这个过滤器,然后在Security自定义配置类进行对应的配置。

请求未认证的接口

当访问没有授权认证的接口,默认的Spring Security会使用AuthenticationEntryPoint将用户请求跳转到登录页面,要求用户提供登录凭证,如果自定义的,可以设置返回的信息进行处理。

  • 未认证处理调用:AuthenticationEntryPoint

需要重写这个过滤器,然后在Security自定义配置类进行对应的配置。

跨域

# 在Security自定义配置类 这里添加 http.cors(withDefaults()); 

获取用户信息

登录页面成功,在其他方法中可以得到当前登录用户的信息

// 存储认证对象的上下文 SecurityContext context = SecurityContextHolder.getContext(); // 认证对象 Authentication authentication = context.getAuthentication(); // 用户名 String username = authentication.getName(); // 身份 Object principal = authentication.getPrincipal(); // 凭证(脱敏) Object credentials = authentication.getCredentials(); //权限 Collection authorities = authentication.getAuthorities(); 

会话并发

当我们同一个用户登录人数过多,会存在账号风险,可通过实现接口SessionInformationExpiredStrategy处理,然后在Security自定义配置类进行对应的配置。

//会话管理 http.sessionManagement(session -> {     session         .maximumSessions(1) // 代表当前登录同一个用户,数量超过1,触发该逻辑         .expiredSessionStrategy(new MySessionInformationExpiredStrategy()); // 重写的SessionInformationExpiredStrategy接口,处理返回逻辑 }); 

授权

  • 用户-权限-资源:例如张三的权限是添加用户、查看用户列表,李四的权限是查看用户列表
  • 用户-角色-权限-资源:例如 张三是角色是管理员、李四的角色是普通用户,管理员能做所有操作,普通用户只能查看信息

用户权限资源的配置:

// 1.配置权限 [自定义配置] http.authorizeRequests(     authorize -> authorize     //具有LIST权限的用户可以访问/user/list     .requestMatchers("/user/list").hasAuthority("LIST")     //具有ADD权限的用户可以访问/user/add     .requestMatchers("/user/save").hasAuthority("ADD")     //对所有请求开启授权保护     .anyRequest()     //已认证的请求会被自动授权     .authenticated() );  // 2 在登录页的接口,为当前登录的用户,赋值给对应的权限列表。  Collection authorities = new ArrayList<>();  authorities.add(() -> "LIST");  authorities.add(() -> "ADD"); 
  • 未授权处理JSON信息调用:AccessDeniedHandler

需要重写这个过滤器,然后在Security自定义配置类进行对应的配置。

用户角色资源配置:

// 1.配置权限 [自定义配置] http.authorizeRequests(     authorize -> authorize     // 具有管理员角色(ADMIN)的用户可以访问/user/**     .requestMatchers("/user/**").hasRole("ADMIN")     //对所有请求开启授权保护     .anyRequest()     //已认证的请求会被自动授权     .authenticated() );  // 2 在登录页的接口,为当前登录的用户,赋值给对应的权限列表。 UserDetails user = new org.springframework.security.core.userdetails.User                     .withUsername(user.getUsername())                     .password(user.getPassword())                     .disabled(!user.getEnabled())  // 是否被禁用                     .credentialsExpired(false)     // 是否过期, false:未过期                     .accountLocked(false)          // 是否锁定, false:没有锁定                     .roles("ADMIN")               // 角色 - 有权限 - 正常访问接口 //                    .roles("ADMIN222")           // 角色  - 没有授权的角色就是403                     .build(); 

用户角色权限资源配置

这样我们需要四张表(用户表、角色表、权限表、用户角色关联表),用户可以被分配一个或多个角色,而每个角色又可以具有一个或多个权限,通过对用户角色关联和角色权限关联表进行操作,可以管理访问权限。

# 用户表: user_id   int      用户ID   username  varchar  用户名   password  varchar  密码  # 角色表: role_id   int      角色ID name      varchar  角色名称 des       varchar  描述  # 权限表: permission_id int  权限ID name      varchar  权限名称 des       varchar  描述  # 角色权限关联表 role_permission_id int  角色权限关联ID role_id   int      角色ID permission_id int  权限ID 

基于方法的授权

在配置文件中添加如下注解

@EnableMethodSecurity 

在用户登录授权,进行授权角色或者权限资源

// 一般我们的角色、权限资源是通过SQL数据库中获取的 UserDetails user = org.springframework.security.core.userdetails.User         .withUsername(user.getUsername())         .password(user.getPassword())         .disabled(!user.getEnabled())  // 是否被禁用         .credentialsExpired(false)     // 是否过期, false:未过期         .accountLocked(false)          // 是否锁定, false:没有锁定         .roles("ADMIN")                // 角色配置         .authorities("USER_ADD", "USER_UPDATE")  // 权限资源,一但配置,上面的 roles 角色,会失效         .build(); 

常用授权注解

//用户必须有 ADMIN 角色 并且 用户名是 admin 才能访问此方法 @PreAuthorize("hasRole('ADMIN') and authentication.name == 'admim'") @GetMapping("/list") public String getList(){     return "list接口,返回信息”; }  //用户必须有 USER_ADD 权限 才能访问此方法 @PreAuthorize("hasAuthority('USER_ADD')") @PostMapping("/add") public void add(@RequestBody User user){     return "add接口,返回信息”; } 

OAuth2简介

OAuth2是一种开放授权协议。

OAuth 2协议包含以下角色:

  1. 资源所有者(Resource Owner):即用户,资源的拥有人,想要通过客户应用访问资源服务器上的资源。
  2. 客户应用(Client):通常是一个Web或者无线应用,它需要访问用户的受保护资源。
  3. 资源服务器(Resource Server):存储受保护资源的服务器或定义了可以访问到资源的API,接收并验证客户端的访问令牌,以决定是否授权访问资源。
  4. 授权服务器(Authorization Server):负责验证资源所有者的身份并向客户端颁发访问令牌。

相关内容

热门资讯

记者发布!wepoke软件透明... 记者发布!wepoke软件透明挂存在的(有挂的)中至卧龙辅助下载(有挂手册),亲,有的,ai轻松简单...
最新通报!wpk插件靠谱的(有... 最新通报!wpk插件靠谱的(有挂的)南宁老友麻将攻略(有挂方式);老友麻将最新版本免费下载安装哦,具...
2024版教程!微扑克可以用模... 2024版教程!微扑克可以用模拟器(有科技)战神牛牛外挂(有挂启发);WPK必备黑科技是一款具有ia...
每日必看推荐!wpk微扑克真的... 每日必看推荐!wpk微扑克真的有助辅的(辅助挂)微信白金岛跑胡子辅助工具(有挂启发);人气非常高,a...
普及知识!wepoke用模拟器... 普及知识!wepoke用模拟器有用(有科技)旺旺闽南麻将有挂的(有挂教导)是一款可以让一直输的玩家,...
新2024版脚本!微扑克辅助器... 新2024版脚本!微扑克辅助器代码(辅助挂)牌乐门手机麻将可以设置输赢的(有挂总结)准备好在wepo...
如何分辨真伪!微扑克为一直输(... 1、完成微扑克的残局,帮助玩家取得所有比赛的胜利,直登高塔的教程。2、多达1000个不同的游戏攻略,...
查到实测!wepoke游戏数据... 查到实测!wepoke游戏数据有说法的(有辅助挂)越乡游棋牌有挂的(有挂规律);wepoke最新版本...
玩家必看!wepoke 插件(... 玩家必看!wepoke 插件(辅助挂)欢乐斗地主助手神器(有挂辅导);超受欢迎的wepoke小游戏,...
关于!德州ai辅助神器(有辅助... 关于!德州ai辅助神器(有辅助挂)gm互娱有挂的(有挂指点);原来是有辅助挂的,本文通常探讨探讨外挂...