问题
The following line doesn't let me visit GET: /api/topics without a bearer token. It works if I apply a token. Am I missing something? Isn't permitAll supposed to do that?
.antMatchers("/api/topics/**").permitAll()
By the way, I tried with /api/topics** and it didn't work as well.
Error:
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
Result without a token (the broken part). I want it to let me through.
Result with a token. It works as intended:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/topics/**").permitAll()
.antMatchers("/api/users/**").permitAll()
.anyRequest().authenticated();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
@RestController
@RequestMapping("/api/topics")
public class TopicController {
@Autowired
private TopicService topicService;
@Autowired
private UserService userService;
@Autowired
private TopicMapper topicMapper;
/**
* Gets all topics.
*
* @return the topics.
*/
@GetMapping
public ResponseEntity<List<TopicDTO>> getAll() {
return ResponseEntity.ok(topicMapper.toTopicDTOs(topicService.getAll()));
}
/**
* Gets topic by id.
*
* @param id the id.
* @return the topic.
*/
@GetMapping("/{id}")
public ResponseEntity<TopicDTO> get(@PathVariable("id") Long id) {
Optional<TopicEntity> topicEntity = topicService.get(id);
return topicEntity.map(entity -> ResponseEntity.ok(topicMapper.toTopicDTO(entity))).orElseGet(() -> ResponseEntity.notFound().build());
}
/**
* Creates a new topic.
*
* @param topicDTO the topic DTO.
* @return the new topic DTO.
*/
@PostMapping
public ResponseEntity<TopicDTO> create(@RequestBody TopicDTO topicDTO) {
UserEntity userEntity = userService.get(topicDTO.getUserId()).orElseThrow(() -> new IllegalArgumentException("User does not exist."));
TopicEntity topicEntity = topicMapper.toTopicEntity(topicDTO);
topicEntity.setId(null);
topicEntity.setUser(userEntity);
Optional<TopicEntity> createdTopicEntity = topicService.create(topicEntity);
return createdTopicEntity.map(entity -> ResponseEntity.ok(topicMapper.toTopicDTO(entity))).orElseGet(() -> ResponseEntity.status(HttpStatus.CONFLICT).build());
}
/**
* Updates an existing topic.
* @param id the topic id.
* @param topicDTO the topic DTO.
* @return the updated topic DTO.
*/
@PutMapping("/{id}")
public ResponseEntity<TopicDTO> update(@PathVariable("id") Long id, @RequestBody TopicDTO topicDTO) {
UserEntity userEntity = userService.get(topicDTO.getUserId()).orElseThrow(() -> new IllegalArgumentException("User does not exist."));
TopicEntity topicEntity = topicMapper.toTopicEntity(topicDTO);
topicEntity.setId(id);
topicEntity.setUser(userEntity);
Optional<TopicEntity> updatedTopicEntity = topicService.update(topicEntity);
return updatedTopicEntity.map(entity -> ResponseEntity.ok(topicMapper.toTopicDTO(entity))).orElseGet(() -> ResponseEntity.badRequest().build());
}
/**
* Deletes an existing topic.
* @param id the topic id.
* @return the status code.
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable("id") Long id) {
if (topicService.get(id).isPresent()) {
topicService.delete(id);
return ResponseEntity.ok().build();
}
return ResponseEntity.notFound().build();
}
}
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private TokenStore tokenStore;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("trusted")
.secret(bCryptPasswordEncoder.encode("secret"))
.authorizedGrantTypes("password", "get_token", "refresh_token")
.scopes("read", "write")
.autoApprove(true)
.accessTokenValiditySeconds(15 * 60)
.refreshTokenValiditySeconds(30 * 60);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.tokenStore(tokenStore);
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration {
}
回答1:
Because @EnableResourceServer will add its filter chain at order=3 by default.As for WebSecurityConfigurerAdapter implementation, adds its own filterchain at the order=100, as a result, request first goes through filter chain of set by @EnableResourceServer where everything is protected unless you provide token and that's why you are getting that behavior. Try to add order bellow 3 like @Order(2) annotation to your WebSecurityConfigurerAdapter implementation.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Order(2) <<--- add this
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
...
}
For more information read: Changing the Filter Order
回答2:
There is a mistake with URL patterns in antMatchers.
By default the pattern like /api/topics/** doesn't match /api/topics.
It matches only /api/topics/ and after slash can be zero or more symbols
For fixing this case can be several solutions:
- Change the pattern in existing antMatchers to next
/api/topics** - Use mvcMatchers instead of antMatchers.
mvcMatchers("/api/topics").permitAll()
mvcMatchers - will use the same rules that Spring MVC uses for matching. For example, often times a mapping of the path "/path" will match on "/path", "/path/", "/path.html", etc.
More information about antMatchers can be found here
More information about mvcMatchers can be found here
来源:https://stackoverflow.com/questions/61031784/antmatchers-permitall-doesnt-let-me-visit-the-rest-point