You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot+Spring Security角色权限控制:如何管控页面访问权限?

基于角色控制Spring Boot Web页面权限的实现方案

看起来你已经搞定了用户登录和角色关联的基础功能,这很棒!接下来要实现特定页面(比如Match.html)仅对管理员开放的需求,核心就是在Spring Security的配置类里定义路径的访问权限规则。我分两种常见的配置方式给你说明:

方式一:使用传统的WebSecurityConfigurerAdapter(适合Spring Security 5.7之前版本)

你需要创建一个继承自WebSecurityConfigurerAdapter的配置类,并重写configure(HttpSecurity http)方法来设置权限规则:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // 注入你已经实现好的UserDetailsService
    @Autowired
    private UserDetailsService customUserDetailsService;

    // 配置密码编码器(确保和用户注册/加密时一致)
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsService)
            .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // 配置请求权限规则
            .authorizeRequests()
                // 公共资源:登录页、静态资源(CSS/JS/图片)允许所有用户访问
                .antMatchers("/login", "/css/**", "/js/**", "/images/**").permitAll()
                // 指定Match.html及其相关接口仅允许ADMIN角色访问
                .antMatchers("/Match.html", "/match/**").hasRole("ADMIN")
                // 其他所有请求都需要先登录认证
                .anyRequest().authenticated()
            .and()
                // 配置自定义登录页面(如果你的登录页不是默认的)
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/home") // 登录成功后的默认跳转页
                .permitAll()
            .and()
                // 配置登出功能
                .logout()
                .permitAll()
            .and()
                // 可选:配置无权限时的跳转页面
                .exceptionHandling()
                .accessDeniedPage("/access-denied");
    }
}

关键细节说明:

  • hasRole("ADMIN"):Spring Security默认会给角色自动加上ROLE_前缀,所以如果你的数据库中角色存储的是ADMIN,这里用hasRole("ADMIN")等价于hasAuthority("ROLE_ADMIN")。如果你的角色存储没有前缀,要么在UserDetailsService里给角色加上ROLE_,要么配置去掉默认前缀:
    @Bean
    public GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return new GrantedAuthorityDefaults(""); // 移除ROLE_前缀
    }
    
  • 路径匹配:/match/**是用来匹配Match.html对应的后端接口(如果有的话),确保接口也受权限控制。

方式二:使用新版本的SecurityFilterChain(Spring Security 5.7+推荐)

如果你用的是较新的Spring Security版本,官方推荐放弃WebSecurityConfigurerAdapter,改用SecurityFilterChain来配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private UserDetailsService customUserDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login", "/css/**", "/js/**", "/images/**").permitAll()
                .requestMatchers("/Match.html", "/match/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/home")
                .permitAll()
            )
            .logout(logout -> logout.permitAll())
            .exceptionHandling(exception -> exception
                .accessDeniedPage("/access-denied")
            );

        return http.build();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(customUserDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }
}

最后要确认的点:

确保你的UserDetailsService实现中,正确把用户的角色封装成GrantedAuthority对象,比如:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    // 从数据库获取用户信息
    User user = userRepository.findByUsername(username);
    if (user == null) {
        throw new UsernameNotFoundException("用户不存在");
    }
    // 把用户角色转换为GrantedAuthority
    List<GrantedAuthority> authorities = user.getRoles().stream()
        .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
        .collect(Collectors.toList());
    return new org.springframework.security.core.userdetails.User(
        user.getUsername(),
        user.getPassword(),
        authorities
    );
}

这样配置后,普通用户访问Match.html时会被跳转到登录页(如果未登录),或者跳转到你配置的access-denied页面(如果已登录但没有ADMIN角色),而管理员就能正常访问啦。

内容的提问来源于stack exchange,提问作者Lucia

火山引擎 最新活动