You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:32:53