先容
您是否曾经构建过应用程序,然后突然意识到需要以更精细的方式管理用户访问权限?也许您已经硬编码了一些管理检查或在整个代码库中分散了权限逻辑。信赖我,我经历过这种情况,维护起来并不好玩。
这就是基于脚色的访问控制 (RBAC) 的作用所在。这是一种基于用户脚色管理用户权限的标准化方法,可让您的应用程序更安全、更易于维护。在这篇文章中,我将引导您使用 MongoDB 在 Spring Boot 应用程序中实现 RBAC。我们将先容从设置项目到保护您的端点的全部内容。
先决条件
在深入研究之前,请确保您已举行以下设置:
- Java 开发工具包 (JDK) 17 或更高版本:Spring Boot 3.x 需要 Java 17+。
- Spring Boot 3.x
- Spring Security 6.x
- MongoDB 6.x
您还需要对以下内容有基本的相识:
- Java 编程
- Spring 框架
- MongoDB
设置项目
1. 创建一个新的 Spring Boot 项目
首先,让我们设置我们的 Spring Boot 项目。您可以使用 Spring Initializr 或您最喜好的 IDE。包罗以下依赖项:
- Spring Web
- Spring Security
- Spring Data MongoDB
- Lombok (可选但强烈发起镌汰样板代码)
2. 更新 pom.xml
确保您的 pom.xml 文件包罗必要的依赖项:
- <project ...>
- <!-- ... other configurations ... -->
- <dependencies>
- <!-- Spring Boot Starter Web -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <!-- Spring Boot Starter Security -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
- <!-- Spring Data MongoDB -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-mongodb</artifactId>
- </dependency>
- <!-- Lombok (Optional) -->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.18.24</version>
- <scope>provided</scope>
- </dependency>
- <!-- ... other dependencies ... -->
- </dependencies>
- <!-- ... other configurations ... -->
- </project>
复制代码 设置 MongoDB
1. 添加 MongoDB 连接详细信息
我们需要将应用程序连接到 MongoDB。在您的 application.properties 或中 application.yml,添加以下内容:
- spring.data.mongodb.uri=mongodb://localhost:27017/rbac_db
复制代码 请随意将 rbac_db 替换为您喜好的数据库名称。
定义实体
现在,让我们定义 RBAC 系统的核心实体:Permission、Role 和 User。
1. Permission.java
- package com.example.rbac.model;
- import org.springframework.data.annotation.Id;
- import org.springframework.data.mongodb.core.mapping.Document;
- import lombok.Data;
- @Data
- @Document(collection = "permissions")
- public class Permission {
- @Id
- private String id;
- private String name;
- }
复制代码 2. Role.java
- package com.example.rbac.model;
- import org.springframework.data.annotation.Id;
- import org.springframework.data.mongodb.core.mapping.Document;
- import lombok.Data;
- import java.util.Set;
- @Data
- @Document(collection = "roles")
- public class Role {
- @Id
- private String id;
- private String name;
- private Set<Permission> permissions;
- }
复制代码 3. User.java
- package com.example.rbac.model;
- import org.springframework.data.annotation.Id;
- import org.springframework.data.mongodb.core.mapping.Document;
- import lombok.Data;
- import java.util.Set;
- @Data
- @Document(collection = "users")
- public class User {
- @Id
- private String id;
- private String username;
- private String password; // We'll store hashed passwords
- private Set<Role> roles;
- }
复制代码 简要阐明:始终以哈希格式存储暗码。稍后我们将先容如何对暗码举行哈希处理。
创建存储库
存储库是我们的应用程序和数据库之间的桥梁。让我们为我们的实体创建它们
1. UserRepository.java
- package com.example.rbac.repository;
- import org.springframework.data.mongodb.repository.MongoRepository;
- import com.example.rbac.model.User;
- public interface UserRepository extends MongoRepository<User, String> {
- User findByUsername(String username);
- }
复制代码 2. RoleRepository.java
- package com.example.rbac.repository;
- import org.springframework.data.mongodb.repository.MongoRepository;
- import com.example.rbac.model.Role;
- public interface RoleRepository extends MongoRepository<Role, String> {
- Role findByName(String name);
- }
复制代码 3. PermissionRepository.java
- package com.example.rbac.repository;
- import org.springframework.data.mongodb.repository.MongoRepository;
- import com.example.rbac.model.Permission;
- public interface PermissionRepository extends MongoRepository<Permission, String> {
- Permission findByName(String name);
- }
复制代码 实现 UserDetailsService
为了与 Spring Security 集成,我们将实现一个自定义的 UserDetailsService。
CustomUserDetailsService.java
- package com.example.rbac.service;
- import org.springframework.security.core.userdetails.*;
- import org.springframework.stereotype.Service;
- import com.example.rbac.model.User;
- import com.example.rbac.model.Role;
- import com.example.rbac.model.Permission;
- import com.example.rbac.repository.UserRepository;
- import java.util.*;
- import org.springframework.security.core.authority.SimpleGrantedAuthority;
- @Service
- public class CustomUserDetailsService implements UserDetailsService {
- private final UserRepository userRepository;
- public CustomUserDetailsService(UserRepository userRepository) {
- this.userRepository = userRepository;
- }
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- User user = userRepository.findByUsername(username);
- if (user == null) {
- throw new UsernameNotFoundException("User not found");
- }
- return new org.springframework.security.core.userdetails.User(
- user.getUsername(),
- user.getPassword(),
- getAuthorities(user.getRoles())
- );
- }
- private Collection<SimpleGrantedAuthority> getAuthorities(Set<Role> roles) {
- Set<SimpleGrantedAuthority> authorities = new HashSet<>();
- for (Role role : roles) {
- authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
- for (Permission permission : role.getPermissions()) {
- authorities.add(new SimpleGrantedAuthority(permission.getName()));
- }
- }
- return authorities;
- }
- }
复制代码 这里发生了什么?
- 我们使用用户名从数据库中获取用户。
- 我们构造一个Spring Security 可以用于身份验证的 UserDetails 对象。
- 我们将脚色和权限转换为 GrantedAuthority 的聚集。
设置 Spring Security
现在,让我们设置 Spring Security 来使用我们的自定义 UserDetailsService。
SecurityConfig.java
- package com.example.rbac.config;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.config.annotation.authentication.builders.*;
- import org.springframework.security.config.annotation.web.builders.HttpSecurity;
- import org.springframework.security.web.SecurityFilterChain;
- import com.example.rbac.service.CustomUserDetailsService;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- @Configuration
- public class SecurityConfig {
- private final CustomUserDetailsService userDetailsService;
- public SecurityConfig(CustomUserDetailsService userDetailsService) {
- this.userDetailsService = userDetailsService;
- }
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- http
- .csrf(csrf -> csrf.disable())
- .authorizeHttpRequests(authz -> authz
- .requestMatchers("/admin/**").hasRole("ADMIN")
- .requestMatchers("/user/**").hasRole("USER")
- .anyRequest().authenticated()
- )
- .formLogin(form -> form
- .loginPage("/login").permitAll()
- )
- .logout(logout -> logout.permitAll());
- return http.build();
- }
- @Bean
- public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
- return http
- .getSharedObject(AuthenticationManagerBuilder.class)
- .userDetailsService(userDetailsService)
- .passwordEncoder(passwordEncoder())
- .and()
- .build();
- }
- @Bean
- public BCryptPasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
- }
复制代码 要点:
- 禁用 CSRF:为简朴起见,我们禁用 CSRF。在生产情况中,请确保正确设置 CSRF 保护。
- 授权规则:
- /admin/** 端点需要 ADMIN 脚色。
- /user/** 端点需要 USER 脚色。
- 全部其他请求都需要身份验证。
- 表单登录: 我们在 指定自定义登录页面 /login。
安全管理暗码
安全至关紧张,尤其是用户暗码。确保在存储暗码之前对其举行哈希处理。
UserService.java
- package com.example.rbac.service;
- import org.springframework.stereotype.Service;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import com.example.rbac.model.User;
- import com.example.rbac.repository.UserRepository;
- @Service
- public class UserService {
- private final UserRepository userRepository;
- private final BCryptPasswordEncoder passwordEncoder;
- public UserService(UserRepository userRepository, BCryptPasswordEncoder passwordEncoder) {
- this.userRepository = userRepository;
- this.passwordEncoder = passwordEncoder;
- }
- public void saveUser(User user) {
- user.setPassword(passwordEncoder.encode(user.getPassword()));
- userRepository.save(user);
- }
- }
复制代码 为什么选择 BCrypt?
BCrypt 是一种盛行的哈希算法,专为哈希暗码而筹划。它包罗盐以防止彩虹表攻击,并且计算密集型以防止暴力攻击。
定义控制器和端点
是时候设置我们的 REST 控制器来处理传入的请求了。
1. AdminController.java
- package com.example.rbac.controller;
- import org.springframework.web.bind.annotation.*;
- @RestController
- @RequestMapping("/admin")
- public class AdminController {
- @GetMapping("/dashboard")
- public String adminDashboard() {
- return "Welcome to the Admin Dashboard!";
- }
- }
复制代码 2. UserController.java
- package com.example.rbac.controller;
- import org.springframework.web.bind.annotation.*;
- @RestController
- @RequestMapping("/user")
- public class UserController {
- @GetMapping("/profile")
- public String userProfile() {
- return "Welcome to your Profile!";
- }
- }
复制代码 处理身份验证
我们将创建一个简朴的控制器来处理登录请求。
WebController.java
- package com.example.rbac.controller;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.GetMapping;
- @Controller
- public class WebController {
- @GetMapping("/login")
- public String login() {
- return "login"; // This should correspond to a Thymeleaf template
- }
- }
复制代码 不要忘记视图!
如果您使用 Thymeleaf,请确保 src/main/resources/templates/ 下有一个 login.html 模板。
创建初始数据
为了测试我们的应用程序,让我们预加载一些脚色、权限和用户。
DataLoader.java
- package com.example.rbac.config;
- import org.springframework.boot.CommandLineRunner;
- import org.springframework.stereotype.Component;
- import com.example.rbac.repository.RoleRepository;
- import com.example.rbac.repository.PermissionRepository;
- import com.example.rbac.repository.UserRepository;
- import com.example.rbac.model.Permission;
- import com.example.rbac.model.Role;
- import com.example.rbac.model.User;
- import com.example.rbac.service.UserService;
- import java.util.Set;
- @Component
- public class DataLoader implements CommandLineRunner {
- private final RoleRepository roleRepository;
- private final PermissionRepository permissionRepository;
- private final UserService userService;
- public DataLoader(RoleRepository roleRepository, PermissionRepository permissionRepository, UserService userService) {
- this.roleRepository = roleRepository;
- this.permissionRepository = permissionRepository;
- this.userService = userService;
- }
- @Override
- public void run(String... args) throws Exception {
- // Create Permissions
- Permission readPermission = new Permission();
- readPermission.setName("READ_PRIVILEGE");
- permissionRepository.save(readPermission);
- Permission writePermission = new Permission();
- writePermission.setName("WRITE_PRIVILEGE");
- permissionRepository.save(writePermission);
- // Create Roles
- Role adminRole = new Role();
- adminRole.setName("ADMIN");
- adminRole.setPermissions(Set.of(readPermission, writePermission));
- roleRepository.save(adminRole);
- Role userRole = new Role();
- userRole.setName("USER");
- userRole.setPermissions(Set.of(readPermission));
- roleRepository.save(userRole);
- // Create Users
- User adminUser = new User();
- adminUser.setUsername("admin");
- adminUser.setPassword("admin123"); // Password will be hashed
- adminUser.setRoles(Set.of(adminRole));
- userService.saveUser(adminUser);
- User normalUser = new User();
- normalUser.setUsername("user");
- normalUser.setPassword("user123"); // Password will be hashed
- normalUser.setRoles(Set.of(userRole));
- userService.saveUser(normalUser);
- }
- }
复制代码 发生了什么?
- 我们创建两个权限:READ_PRIVILEGE 和 WRITE_PRIVILEGE。
- 我们创建两个脚色:ADMIN(具有两个权限)和 USER(具有读取权限)。
- 我们创建两个用户:一个管理员用户和一个普通用户。
测试应用程序
让我们确保统统按预期运行。
1. 运行应用程序
启动您的 Spring Boot 应用程序:
2. 访问登录页面
导航至 http://localhost:8080/login。您应该会看到您的登录页面。
3. 测试用户身份验证
管理员用户
登录后,实行访问:
- http://localhost:8080/admin/dashboard — 应显示管理仪表板。
- http://localhost:8080/user/profile — 应显示用户个人资料。
普通用户
登录后,实行访问:
- http://localhost:8080/user/profile — 应显示用户个人资料。
- http://localhost:8080/admin/dashboard — 应返回 403 Forbidden 错误。
结论
就如许!我们使用 Spring Boot 和 MongoDB 构建了一个简朴但强大的 RBAC 系统。以下是我们所完成工作的简要回顾:
- 设置项目:使用必要的依赖项初始化 Spring Boot 项目。
- 设置 MongoDB:将我们的应用程序连接到 MongoDB 数据库。
- 定义的实体:创建 User、Role 和 Permission 模型。
- 创建的存储库:设置用于数据访问的存储库。
- 实现 UserDetailsService:将我们的用户模型与 Spring Security 集成。
- 设置 Spring Security:设置身份验证和授权规则。
- 安全管理暗码:使用 BCrypt 对暗码举行哈希处理。
- 定义控制器:为不同的脚色创建端点。
- 创建初始数据:预加载的脚色、权限和用户以供测试。
- 测试应用程序:验证我们的 RBAC 系统是否按预期工作。
下一步:
您可以通过添加更多脚色、权限和安全端点来扩展此应用程序。您还可以集成 JWT 举行无状态身份验证或添加前端以与您的 API 交互。
其他最佳实践
虽然我们已经先容了底子知识,但另有以下一些最佳做法可供思量:
- 验证:@NotNull 使用和等注释 @Size 来验证用户输入。
- 非常处理:用实现全局非常处理 @ControllerAdvice。
- 日记记载:利用日记框架实现更好的可追溯性。
- 安全标头:设置标头以防止常见的漏洞。
- CORS 设置:如果您有前端应用程序,请得当设置跨域资源共享。
文章原地址
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |