古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
个人CSND主页——Micro麦可乐的博客
《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
《RabbitMQ》专栏主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~
回顾链接:
最新Spring Security实战教程(一)初识Spring Security安全框架
最新Spring Security实战教程(二)表单登录定制到处理逻辑的深度改造
最新Spring Security实战教程(三)Spring Security 的底层原理解析
又是新的一周,博主继续来给大家更新 Spring Security
实战教程了,在上一个章节中我们详细介绍了 Spring Security
的底层原理,本章节博主将带着大家介绍如何在 Spring Security
中实现基于内存的用户认证。
虽然 Spring Security
基于内存的用户认证,实际开发来说相对来说用的比较少,但某些场景下(如:开发阶段、原型验证、演示环境搭建、单元测试/集成测试、或甚至不需要数据库的简单系统),基于内存的用户认证方式就足以满足需求,为了应对这样需求,博主觉得还是要必要聊一聊基于内存的用户认证。
就如前面说的场景,总结内存认证主要有以下几个优点:
当然,内存认证也有局限性:用户数据不持久化、无法扩展到分布式系统等。因此,在生产环境中,通常会采用基于数据库或其他外部认证机制的方式。
与数据库认证对比
特性 | 内存认证 | 数据库认证 |
---|---|---|
用户存储位置 | 应用内存 | 持久化存储 |
用户管理灵活性 | 配置硬编码 | 动态增删改查 |
生产环境适用性 | 不推荐 | 推荐 |
接下来在之前的Maven项目中还是创建第三个子模块 memory-spring-security
,完整的maven项目结构如下:
现在我们来创建一个Spring Security
配置文件 InMemorySecurityConfig
@Configuration
public class InMemorySecurityConfig {
// 手动配置用户信息
@Bean
public UserDetailsService users() {
UserDetails user = User.withUsername("user")
.password("{noop}user") // {noop}表示不加密
.roles("USER")
.build();
UserDetails admin = User.withUsername("admin")
.password("{noop}admin")
.roles("ADMIN")
.build();
//可以继续追加其它用户...
UserDetails anonymous = User.withUsername("anonymous")
.password("{noop}anonymous")
.roles("ANONYMOUS")
.build();
return new InMemoryUserDetailsManager(user, admin, anonymous);
}
// 配置安全策略 并配置/admin/** 只允许ADMIN角色用户访问
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.
authorizeHttpRequests(authorize -> authorize
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.logout(withDefaults())
;
return http.build();
}
}
配置说明
- 构建UserDetailsService
创建两个用户信息分别是:admin、user ,并由InMemoryUserDetailsManager
进行在内存中保存用户数据- SecurityFilterChain
在SecurityFilterChain
中,默认采用了Spring Security表单登陆登出方式,并配置/admin/**
请求路径下需要管理员角色方可访问
接下来我们创建用以测试的Controller :DemoMemoryController
@Controller
public class DemoMemoryController {
//返回用户信息及角色权限
@GetMapping("/")
public ResponseEntity<Map<String, Object>> index(Authentication authentication) {
String username = authentication.getName();//用户名
Object principal =authentication.getPrincipal();//身份
// 获取用户拥有的权限列表
List<String> roles = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
//返回用户信息
return ResponseEntity.ok(Map.of(
"username", username,
"principal", principal,
"roles", roles));
}
//测试管理员权限
@GetMapping("/admin/view")
public ResponseEntity<String> admin() {
return ResponseEntity.ok("管理员ADMIN角色访问ok");
}
}
代码说明
- 注入 Authentication 对象
在index
方法中,通过方法参数直接注入Authentication
对象,Spring Security
会自动传入当前认证信息。- 提取用户信息
通过authentication.getName()
获取当前登录用户的用户名;通过authentication.getAuthorities()
获取用户的权限列表,并将每个权限的 getAuthority() 值收集成一个字符串列表。
启动项目访问,登陆页中分别测试两个用户登陆查看信息,如user用户:
接下来尝试使用user用户访问 /admin/view 路径,会出现 403 访问错误提示:即您无权访问此地址
切换admin用户登陆,继续访问 /admin/view 路径,出现 管理员ADMIN角色访问ok 文字显示即代表管理员角色允许访问
在上述代码中,我们使用了 password(“{noop}admin”) 声明了密码明文存储,如果我们需要对密码加密,如何操作? 实际上 Spring Security
为我们提供了非常方便的密码编码器
密码编码器配置
只需要创建 PasswordEncoder
Bean,并返回加密类型,如下代码样例:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService users(PasswordEncoder encoder) {
UserDetails user = User.builder()
.username("user")
.password(encoder.encode("secret"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
支持的编码格式:
# 不同前缀对应不同编码器
{noop} → NoOpPasswordEncoder (明文)
{bcrypt} → BCryptPasswordEncoder
{pbkdf2} → Pbkdf2PasswordEncoder
{scrypt} → SCryptPasswordEncoder
{sha256} → StandardPasswordEncoder
通过本章节的配置示例,相信你已经可以使用 Spring Security
的基于内存认证方式来快速搭建安全认证体系。
注意章节中提到的基于内存的用户认证适用的场景,更多情况下还是建议使用更为健全的认证方式,如 基于数据库的认证、JWT 令牌认证或 OAuth2,在下一章节我们将重点讲述数据库的认证,敬请期待…
如果本本章内容对您有所帮助,希望 一键三连 给博主一点点鼓励,如果您有任何疑问或建议,请随时留言讨论!
下一章节:最新Spring Security实战教程(五)基于数据库的动态认证 - UserDetailsService实战开发