Spring Boot 3.0.4多实体角色权限配置及登录实现求助
我正在开发基于MVC的Spring Boot 3.0.4项目,需集成Spring Security实现电子大学日记系统。系统预设Student和Professor实体数据,无需注册仅需登录,需为两者分配STUDENT和PROFESSOR角色,实现如下权限控制:
.antMatchers("/student/**").hasRole("STUDENT") .antMatchers("/professor/**").hasRole("PROFESSOR")
现有Student、Professor实体及对应JpaRepository,此前自行编写了登录控制器与Thymeleaf登录页,但未使用Spring Security,不清楚如何配置安全规则、登录逻辑,也不确定是否需创建角色表并建立关联,寻求解决方案。
1. 角色设计调整
当前场景下无需单独创建角色表,Student和Professor本身属于固定角色类型,登录时直接为用户分配对应角色即可。若后续需扩展多角色,再考虑添加角色关联表。
2. 添加Spring Security依赖
Maven(pom.xml)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
Gradle(build.gradle)
implementation 'org.springframework.boot:spring-boot-starter-security'
3. 实现UserDetailsService
自定义UserDetailsService实现类,统一处理Student和Professor的用户信息加载:
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Service; @Service public class CustomUserDetailsService implements UserDetailsService { private final StudentRepository studentRepository; private final ProfessorRepository professorRepository; public CustomUserDetailsService(StudentRepository studentRepository, ProfessorRepository professorRepository) { this.studentRepository = studentRepository; this.professorRepository = professorRepository; } @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { // 优先查询学生 Student student = studentRepository.findByEmail(email); if (student != null) { return User.builder() .username(student.getEmail()) .password(student.getPassword()) .roles("STUDENT") .build(); } // 查询教授 Professor professor = professorRepository.findByEmail(email); if (professor != null) { return User.builder() .username(professor.getEmail()) .password(professor.getPassword()) .roles("PROFESSOR") .build(); } throw new UsernameNotFoundException("用户不存在: " + email); } }
需在StudentRepository和ProfessorRepository中添加
findByEmail(String email)方法,例如:// StudentRepository中 Student findByEmail(String email);
4. 配置Spring Security安全规则
创建Security配置类,定义权限控制、登录路径及跳转逻辑:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/login", "/css/**", "/js/**").permitAll() // 允许访问登录页及静态资源 .requestMatchers("/student/**").hasRole("STUDENT") .requestMatchers("/professor/**").hasRole("PROFESSOR") .anyRequest().authenticated() // 其余请求需认证 ) .formLogin(form -> form .loginPage("/login") // 指定自定义登录页路径 .loginProcessingUrl("/authenticateTheUser") // 登录提交接口,与登录页form action一致 .defaultSuccessUrl("/default", true) // 登录成功默认跳转页 .permitAll() ) .logout(logout -> logout .permitAll() ); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
5. 调整登录控制器与页面
简化登录控制器
Spring Security会自动处理登录验证逻辑,无需手动编写认证代码,调整后的控制器如下:
import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class LoginController { @GetMapping("/login") public String loginPage() { return "login-page"; } // 根据用户角色跳转对应页面 @GetMapping("/default") public String defaultPage(Authentication authentication) { for (GrantedAuthority authority : authentication.getAuthorities()) { if ("ROLE_STUDENT".equals(authority.getAuthority())) { return "redirect:/student/menu"; } else if ("ROLE_PROFESSOR".equals(authority.getAuthority())) { return "redirect:/professor/menu"; } } return "login"; } }
需确保
/student/menu和/professor/menu已实现对应的控制器方法与页面。
调整Thymeleaf登录页
修改表单参数名以匹配Spring Security默认规则,同时添加错误提示:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en"> <head> <title>登录页面</title> </head> <body> <h2>登录页面</h2> <form th:action="@{/authenticateTheUser}" method="POST"> <div> <label for="email">邮箱:</label> <input type="email" id="email" name="username" required /> </div> <div> <label for="password">密码:</label> <input type="password" id="password" name="password" required /> </div> <div> <button type="submit">登录</button> </div> <!-- 登录错误提示 --> <div th:if="${param.error}" style="color: red;"> 邮箱或密码错误 </div> </form> </body> </html>
若不想修改参数名,可在SecurityConfig的
formLogin中添加.usernameParameter("email")指定用户名参数为email。
6. 密码加密处理
Spring Security要求密码必须加密存储,需对预设的Student和Professor密码进行BCrypt加密,示例代码:
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; public class PasswordEncoderTest { public static void main(String[] args) { BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); String rawPassword = "student123"; // 原始密码 String encodedPassword = encoder.encode(rawPassword); System.out.println(encodedPassword); // 生成加密后的密码,存入数据库 } }
必须确保数据库中存储的是加密后的密码,否则登录会失败。
内容的提问来源于stack exchange,提问作者Gordey

