权限不生效,配置类如下:
```java
@Configuration
//@EnableGlobalMethodSecurity(prePostEnabled = true) //开启全局安全认证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private UserDetailsService userDetailsService;
@Resource
private AuthenticationHandler authenticationHandler;
@Resource
private AuthenticationTokenFilter AuthenticationTokenFilter;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS,"/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
http
// CSRF禁用,因为不使用session
.csrf().disable()
// 认证失败处理类,指定异常处理实现类
.exceptionHandling().authenticationEntryPoint(authenticationHandler).and()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 过滤请求
.authorizeRequests()
// .antMatchers("/admin/**")
// //.hasRole("ADMIN")
// .hasAnyRole("ADMIN")
//.mvcMatchers("/admin/**").hasRole("admin")
//.antMatchers("/admin/**").hasRole("ROLE_admin") //访问/admin/**下的路径,必须具备admin身份
// .antMatchers("/ordinary/**").hasRole("ordinary") //访问/ordinary/**下的路径,必须具备user身份
//对于登录login 验证码 允许匿名访问
.antMatchers("/user/getcode", "/user/login","/login/**").permitAll()
.antMatchers("/admin/**").hasAnyAuthority("admin")
//其他全部拦截认证
.anyRequest()
.authenticated();
//将认证过滤器添加到security中
http.addFilterBefore(AuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
/**
* 设置加密方式
*
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//授权时去掉默认角色前缀"ROLE_"
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
}
}
接口:
@Slf4j
@RestController
@RequestMapping("/admin")
@CrossOrigin //关闭跨域验证
public class AdminTestController {
//@PreAuthorize("hasAnyRole('ADMIN')")
//@PreAuthorize("hasAuthority('PERMISSION_TEST')")
//@Secured({"admin:select"})
@GetMapping("/test")
public R test() {
return R.success("admin权限测试成功");
}
}
权限:
```java
@AllArgsConstructor
@NoArgsConstructor
@Data
public class LoginUser implements UserDetails {
private TUser tUser;
private List<SimpleGrantedAuthority> roles;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return AuthorityUtils.commaSeparatedStringToAuthorityList("admin,nobks");
}
@Override
public String getPassword() {
String pass=tUser.getPassword();
tUser.setPassword("禁止查看");
return pass;
}
@Override
public String getUsername() {
return tUser.getUsername();
}
/**
* 账户是否过期
* @return
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 账户是否锁定
* @return
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
登录后未设置权限的接口正常,但是有权限的就是403
看明白了上面的逻辑,现在不用我说,大家也知道权限通配符在 Spring Security 中是不支持的(无论你在 @PreAuthorize 注解中写的 SpEL 是哪个,调用的是哪个方法,都是不支持权限通配符的)。
例如我现在这样描述我的用户权限:
@Bean
UserDetailsService userDetailsService() {
InMemoryUserDetailsManager m = new InMemoryUserDetailsManager();
m.createUser(User.withUsername("javaboy").password("{noop}123").authorities("system:user:*").build());
return m;
}
我想用 system:user:*
字符串表示 javaboy 具有针对用户的所有权限。
直接这样写肯定是不行的,最终字符串比较一定是不会通过的。
那么怎么办呢?用正则似乎也不太行,因为 * 在正则中不代表所有字符,如果拆解字符串去比较,功能虽然也行得通,但是比较麻烦。
想来想去,想到一个办法,不知道小伙伴们是否还记得我们之前在 vhr 中用过的 AntPathMatcher,用这个不就行了!
修改后的 CustomPermissionEvaluator 如下:
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority authority : authorities) {
if (antPathMatcher.match(authority.getAuthority(), (String) permission)) {
return true;
}
}
return false;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return false;
}
}
修改之后,现在只要用户具备 system:user:*
权限,就四个接口都能访问了。
解决方案:
在这个配置中,您设置了一些接口需要特定的角色才能访问。但是,您提到即使在登录后,您从上下文中获取的用户信息也没有角色信息。这可能意味着您没有正确设置用户的角色信息,也可能是您的角色信息源并未工作。
以下是您可以采取的措施:
1.验证用户角色信息源是否起作用
在您的配置中,您指定了一个MyUserDetailsService
来从数据库中获取用户信息。您需要确保该服务正确设置了用户角色信息。您可以测试该角色源是否工作,方法是从数据库中获取具有适当权限的用户并尝试登录到应用程序中。如果您登录成功并且能够访问受限制的接口,那么可以确认该角色源工作正常。
2.使用内存角色存储
另一种方法是将角色信息存储在内存中。以下是一个示例(仅供参考):
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.anyRequest().permitAll()
.and().formLogin();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("{noop}password").roles("USER")
.and()
.withUser("admin1").password("{noop}password").roles("ADMIN");
}
}
上述代码将在内存中配置两个用户:user1和admin1。它们都有一个密码password和相应的角色USER和ADMIN。请注意,这在生产环境中是不安全的,仅用于测试目的。
3.排除Spring Boot自动配置
如果您使用了Spring Boot,并且您的配置类文件位于应用程序的主包下,则可能会发生Spring Boot自动配置的冲突。为了解决这个问题,请在您的配置类上使用@EnableWebSecurity(debug = true)
查看执行链。
4.添加Spring Security依赖关系
请更新您的项目依赖关系以包含所需版本的Spring Security。
最后,我建议您仔细查看Spring Security文档,特别是有关提供角色信息源的部分。他们提供了许多示例和最佳实践,这有助于您更好地理解并解决这个问题。如果我无法提供有用的解决方案,请不要犹豫联系我。