如何正确使用 Spring Security 中的 hasRole?
Posted
技术标签:
【中文标题】如何正确使用 Spring Security 中的 hasRole?【英文标题】:How to use hasRole in Spring Security properly? 【发布时间】:2021-04-07 20:19:16 【问题描述】:嗨,我试图实现的是保护一个只有一个角色可以访问它的 url,当我尝试添加 .hasRole("USER") 时,其他角色仍然可以访问它。这是我的做法:
这是我的控制器:
@RestController
@RequestMapping("/couponapi")
public class CouponController
@Autowired
CouponRepository couponRepository;
@PostMapping("/coupons")
public Coupon save(@RequestBody Coupon coupon)
return couponRepository.save(coupon);
@GetMapping("/coupons/code")
public Coupon findByCode(@PathVariable("code") String code)
return couponRepository.findByCode(code);
@GetMapping("/something")
public Coupon findByCodeX()
return couponRepository.findByCode("SUPERSALE");
我只想为 ROLE_ADMIN 保护@GetMapping("/something")
,这是我的 Spring 安全配置的样子:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
UserDetailServiceImpl userDetailService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailService);
@Override
protected void configure(HttpSecurity http) throws Exception
http.httpBasic();
http.authorizeRequests()
.antMatchers(HttpMethod.GET,"/couponapi/coupons/**").hasRole("USER")
.antMatchers(HttpMethod.POST,"/couponapi/coupons/**").hasRole("USER")
.antMatchers("/couponapi/something").hasRole("ADMIN")
.antMatchers("/**").authenticated()
.and().httpBasic().and().csrf().disable();
@Bean
public PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
这是我的角色类:
@Data
@EqualsAndHashCode(of = "id")
@ToString(of = "id" )
@Entity
public class Roles implements GrantedAuthority
private static final long serialVersionUID = -7314956574144971210L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "roles")
private Set<Users> users;
@Override
public String getAuthority()
return null;
这是我实现 UserDetailsService 类的服务:
@Service
public class UserDetailServiceImpl implements UserDetailsService
@Autowired
UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException
Users users = userRepository.findByEmail(s);
if(users == null)
throw new UsernameNotFoundException("Username Not Found");
return new User(users.getEmail(), users.getPassword(), users.getRoles());
这是我的数据库角色数据:
如你所见,我有 ROLE_USER 和 ROLE_ADMIN
这是我加入的数据库
** 我刚刚更新了我的问题,我已经回答了一半的问题,请阅读下面的答案以查看最新问题
【问题讨论】:
你可以尝试将hasRole
更改为hasAuthority
,没有任何意义,但如果你可以尝试
当然,我试试这个 .hasAuthority("ROLE_USER") 还是一样的结果,不工作
好的,请在CouponController
中添加一个参数Authentication
并检查其中的所有字段是什么
你的意思是这样吗? @GetMapping("/something") public Coupon findByCodeX(Authentication auth) return couponRepository.findByCode("SUPERSALE"); 我如何检查其中的所有字段人口?
请这样
【参考方案1】:
感谢您对问题的良好介绍。
这就是我所理解的,您只想向具有 Admin 角色的用户授予访问此 URL /couponapi/something
的权限,并为所有经过身份验证的用户授予访问此 URL /couponapi/coupons/**
的访问权限,无论其角色如何(管理员或用户)
尝试使用 hasAuthority
而不是 hasRole
并删除第一行 http.httpBasic()
,它对我有用。
所以在 WebSecurityConfig.java 文件中:
@Override
protected void configure(HttpSecurity http) throws Exception
http.authorizeRequests()
.antMatchers("/couponapi/something").hasAuthority("ROLE_ADMIN")
.antMatchers("/**").authenticated()
.and().httpBasic().and().csrf().disable();
那么在上面的代码中,你只给具有ADMIN权限的用户访问这个url/couponapi/something
,所以具有USER权限的用户不能访问它。
由于您已经声明了密码编码器 bean,您可以将其与 AuthenticationManagerBuilder
一起使用
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
【讨论】:
【参考方案2】:在 Spring Security 中,最严格的规则首先定义,因此您的配置应该如下所示
@Override
protected void configure(HttpSecurity http) throws Exception
http.httpBasic();
http.authorizeRequests()
.antMatchers(HttpMethod.GET,"/**/something").hasRole("USER")
.antMatchers("/**").authenticated()
.and().httpBasic().and().csrf().disable();
【讨论】:
嗨,是的,我想出了一个,但我仍然有关于 HttpMethod.GET 等的问题,我仍然无法让它工作【参考方案3】:我在这里找到了罪魁祸首,但不完全是我仍然缺少 HttpMethod 一的功能。这是我修复角色的方法,在我的 Role 类中,我犯了一个错误,我试图实现 GrantedAuthority 类,导致这个麻烦的事情(没有 HttpMethod 问题)。这就是我修复它的方法
首先,删除 impements 并将角色转换为通常的@Entity 类:
@Data
@EqualsAndHashCode(of = "id")
@ToString(of = "id" )
@Entity
public class Roles
private static final long serialVersionUID = -7314956574144971210L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "roles")
private Set<Users> users;
然后在实现 UserDetailsService 的类中,添加以下代码:
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
users.getRoles().forEach(d ->
grantedAuthorities.add(new SimpleGrantedAuthority(d.getName()));
);
我无法详细解释,但我认为 List 只需要 1 个字符串,即字符串是角色名称。那么这里是完整的代码:
@Service
public class UserDetailServiceImpl implements UserDetailsService
@Autowired
UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException
Users users = userRepository.findByEmail(s);
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
users.getRoles().forEach(d ->
grantedAuthorities.add(new SimpleGrantedAuthority(d.getName()));
);
if(users == null)
throw new UsernameNotFoundException("Username Not Found");
return new User(users.getEmail(), users.getPassword(), grantedAuthorities);
如果有人可以找到此行.antMatchers(HttpMethod.GET,"/**/something").hasRole("USER")
的修复方法,我想使用 HttpMethod 来区分具有相同 url 的每个方法,如果有人有答案,我会接受你的答案。等着呢
【讨论】:
以上是关于如何正确使用 Spring Security 中的 hasRole?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用spring-security,oauth2调整实体的正确登录?
使用 Spring Security 成功登录后如何正确更新登录日期时间?
如何正确使用配置器类实现 Spring Security Ldap 身份验证?
如何正确设置 Spring Security 以使其使用提供的 SSLSocketFactory