Spring Security配置:如何实现多角色组合的页面访问控制?
解决方案
你遇到的问题核心有两点:原SpEL表达式存在语法错误,以及不同Spring Security版本中access方法的参数类型差异。以下是针对性解决方法:
一、修正SpEL表达式(适用于支持access(String)的版本)
如果你的Spring Security版本在5.7之前,authorizeHttpRequests()的access方法支持传入SpEL字符串,只需补充原表达式中缺失的闭合括号即可:
@Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .headers().frameOptions().disable() .and() .authorizeHttpRequests() .antMatchers("/aaa/**", "/bbb/**").permitAll() .antMatchers("/ccc", "/ddd/**").hasRole("AAA") // 修正SpEL语法,补充末尾的闭合括号 .antMatchers("/zzz/**").access("hasRole('AAA') and hasAnyRole('MASTER', 'ZZZ')") // 注意:这行会覆盖后续的anyRequest配置,建议根据实际需求调整或移除 .antMatchers("/**").permitAll() .anyRequest().authenticated() .and() // 后续配置... }
注意:
.antMatchers("/**").permitAll()会匹配所有请求,导致.anyRequest().authenticated()完全失效,建议根据实际开放路径调整这行配置。
二、使用Lambda表达式/自定义授权管理器(适用于Spring Security 5.7+)
5.7版本后官方弃用了WebSecurityConfigurerAdapter,同时access方法不再接受字符串参数,推荐用Lambda表达式或自定义AuthorizationManager实现逻辑:
方式1:直接用Lambda表达式
@Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .headers().frameOptions().disable() .and() .authorizeHttpRequests(auth -> auth .antMatchers("/aaa/**", "/bbb/**").permitAll() .antMatchers("/ccc", "/ddd/**").hasRole("AAA") .antMatchers("/zzz/**").access((authentication, context) -> { Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); // Spring Security的hasRole会自动添加ROLE_前缀,判断时需对应 boolean hasAAA = authorities.stream().anyMatch(a -> a.getAuthority().equals("ROLE_AAA")); boolean hasMasterOrZzz = authorities.stream().anyMatch(a -> a.getAuthority().equals("ROLE_MASTER") || a.getAuthority().equals("ROLE_ZZZ") ); return hasAAA && hasMasterOrZzz ? AuthorizationDecision.authorized() : AuthorizationDecision.denied(); }) .anyRequest().authenticated() ) .and() // 后续配置... }
方式2:封装自定义AuthorizationManager(复用性更强)
// 封装可复用的授权逻辑 private AuthorizationManager<RequestAuthorizationContext> requireAAAAndEitherMasterOrZzz() { return (authentication, context) -> { Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); boolean hasAAA = authorities.stream().anyMatch(a -> a.getAuthority().equals("ROLE_AAA")); boolean hasMasterOrZzz = authorities.stream().anyMatch(a -> a.getAuthority().equals("ROLE_MASTER") || a.getAuthority().equals("ROLE_ZZZ") ); return new AuthorizationDecision(hasAAA && hasMasterOrZzz); }; } @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable() .headers().frameOptions().disable() .and() .authorizeHttpRequests(auth -> auth .antMatchers("/aaa/**", "/bbb/**").permitAll() .antMatchers("/ccc", "/ddd/**").hasRole("AAA") .antMatchers("/zzz/**").access(requireAAAAndEitherMasterOrZzz()) .anyRequest().authenticated() ) .and() // 后续配置... }
内容的提问来源于stack exchange,提问作者gantodagee
相关产品推荐
相关产品推荐

