嗨,我想要实现的是保护只有一个角色可以访问它的网址,当我尝试添加 .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");
}
}
我只想保护
@GetMapping("/something")
只用于 ROLE_ADMIN,这是我的 Spring Security 配置的样子:
@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
这是我加入的数据库
** 我刚刚更新了我的问题,我已经回答了一半的问题,请阅读下面我的答案以查看最新一期
在 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 的功能。这是我修复角色的方法,在我的 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 来区分具有相同网址的每个方法,如果有人有答案,我会接受你的答案。等待它
感谢您对问题的精彩表述。
这就是我的理解,您只想向具有 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());
}
在 Spring Security 6.x 中,我尝试将 hasRole 更改为 hasAuthority 及其工作!