Spring Security:hasAuthority、hasRole 和 PreAuthorize 不起作用
Posted
技术标签:
【中文标题】Spring Security:hasAuthority、hasRole 和 PreAuthorize 不起作用【英文标题】:Spring Security: hasAuthority,hasRole and PreAuthorize does not work 【发布时间】:2020-06-24 02:50:45 【问题描述】:我正在尝试使用标准 Spring Security 注释和方法测试我的 web api。 我查看了网站上的所有选项,没有任何帮助,这是代码。没有角色,一切正常。我已经为这个问题苦恼了好几天。感谢您的帮助,谢谢。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private UserDetailsServiceImp userDetailsService;
@Autowired
JwtFilter jwtFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST,"/authenticate").permitAll()
.antMatchers(HttpMethod.GET,"/userData").permitAll()
.antMatchers(HttpMethod.GET,"/allUsers").hasAuthority("ROLE_ADMIN")
.anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint())
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterAfter(jwtFilter, UsernamePasswordAuthenticationFilter.class);
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Bean
public PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
控制器类
@RestController
public class AuthenticationController
@Autowired
public AuthenticationManager authenticationManager;
@Autowired
private UserDetailsServiceImp userDetailsService;
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserRepository userRepository;
@RequestMapping(value = "/userData", method = RequestMethod.GET)
public String hello()
return "Hello new User";
@RequestMapping(value = "/allUsers", method = RequestMethod.GET)
public List<UserD> findAll()
return userRepository.findAll();
@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest jwtRequest) throws Exception
try
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(jwtRequest.getName(), jwtRequest.getPassword()));
catch(BadCredentialsException e)
throw new Exception("Incorrect username and password", e);
final UserD userD = (UserD)userDetailsService.loadUserByUsername(jwtRequest.getName());
final String token = jwtUtil.generateToken(userD.getName(), userD.getRole());
Map<Object, Object> model = new HashMap<>();
model.put("username", jwtRequest.getName());
model.put("token", token);
return ResponseEntity.ok(model);
如果antMatchers(HttpMethod.GET,"/allUsers").permitAll()
,然后它会返回应有的用户
UserDetailsServiceImp
@Service
public class UserDetailsServiceImp implements UserDetailsService
@Autowired
UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
return userRepository.findByName(username).get(0);
以及添加角色的用户数据
@Component
public class DataInitializer implements CommandLineRunner
@Autowired
UserRepository userRepository;
@Autowired
PasswordEncoder passwordEncoder;
@Override
public void run(String... args) throws Exception
UserD user = new UserD();
user.setName("user");
user.setPassword(passwordEncoder.encode("password"));
user.setRole("ROLE_USER");
userRepository.save(user);
UserD admin = new UserD();
admin.setName("admin");
admin.setPassword(passwordEncoder.encode("password"));
admin.setRole("ROLE_ADMIN");
userRepository.save(admin);
这是数据库返回的内容
【问题讨论】:
【参考方案1】:我想先澄清一点,这可能有助于您查明问题:
您的 UserDetailsServiceImp 是否从数据库或 LDAP 或其他存储库中检索用户名和角色? 从数据库或 LDAP 或其他存储库中检索到什么角色? 有没有前缀“ROLE_”?
如果从数据库中检索到的角色是“ADMIN”,则在调用hasAuthority()时不要自己添加ROLE_。
.antMatchers(HttpMethod.GET,"/allUsers").hasAuthority("ADMIN")
如果不是这样,请在日志中启用调试,以查看 /allUsers 请求到底发生了什么。
更新: 我怀疑的一件事是您对 UserDetailsServiceImp 的实施。
您必须确保将角色设置为用户详细信息。 在您的实现中,您似乎直接从数据库中查询出来,不确定您是否将角色设置为 userDetails。
return userRepository.findByName(username).get(0);
这是应该发生的事情:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
//assume, there is only one user with the username
UserD user = userRepository.findByUsername(username);
if (user == null)
throw new UsernameNotFoundException("User not found with username: " + username);
List<GrantedAuthority> roles = new ArrayList<>();
//assume, there is only one role for the user
roles.add(new SimpleGrantedAuthority(user.getRole()));
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
roles);
【讨论】:
我认为您的 UserDetailsServiceImp 实现可能有问题,请确保在您的“loadUserByUsername”方法中将授予的权限设置为用户。 我还更新了答案以显示如何设置授予的权限。 我添加了截图以上是关于Spring Security:hasAuthority、hasRole 和 PreAuthorize 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security 'Roles' 和 'Privileges' 和 Thymeleaf 'hasRole' 和 'hasAuthority'
Spring security 中的hasAuthority()和hasRole() 有啥区别?
Spring Security 保护路由 hasRole,hasAuthority 不适用于 CORS http 请求