如何在Spring Security 中正确使用hasrole?

sczxawaw  于 2021-06-29  发布在  Java
关注(0)|答案(3)|浏览(534)

嗨,我试图实现的是保护一个url,只有一个角色可以访问它,当我尝试add.hasrole(“用户”)时,其他角色仍然可以访问它。我是这样做的:
这是我的控制器:

@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") 仅针对角色\u admin,以下是我的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());
    }
}

这是我的数据库角色数据:

如您所见,我有角色\用户和角色\管理员
这是我的数据库

**我刚刚更新了我的问题,我有我的问题的一半答案,请阅读我的回答下面看到最新的问题

iezvtpos

iezvtpos1#

我在这里找到了罪魁祸首,但不是全部,我仍然缺少httpmethodone的功能。下面是我如何修复角色的,在我的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()));
});

我不能详细解释,但我认为列表只需要一个字符串,那个字符串是一个角色名。下面是完整的代码:

@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来区分每个方法与相同的网址,如果有人有答案,我会接受你的答案。等着呢

f4t66c6m

f4t66c6m2#

谢谢你对你的问题做了很好的陈述。
这就是我所说的,你只想让管理员角色的用户访问这个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();
    }

然后在上面的代码部分中,您只向具有管理权限的用户授予访问此url的权限 /couponapi/something 所以拥有用户权限的用户不能访问它。
既然您已经声明了一个密码编码器bean,就可以将它与 AuthenticationManagerBuilder ```
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

0lvr5msh

0lvr5msh3#

在springsecurity中,最严格的规则是首先定义的,因此您的配置应该如下所示

@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();
}

相关问题