在与此斗争了几天之后(搜索类似的问题,做试验和错误),我想放弃了……
所以问题是我有一个基于Spring Boot的REST服务,使用Spring Security和JWT进行身份验证。现在,我想保护一些方法,使其仅由使用@PreAuthorize-annotation的授权人员调用。这似乎是可行的,部分原因是Spring没有调用该方法,而是返回404。我还以为是403呢。
我已经阅读了这个SO-question,并尝试了那里给出的答案,但它没有帮助。我已经按照其他地方的建议将@EnableGlobalMethodSecurity(prePostEnabled = true)-Annotation从我的SecurityConfiguration类移动到了应用程序类,但它仍然不起作用。
我的安全配置如下所示:
@Configuration
@Profile("production")
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${adDomain}")
private String adDomain;
@Value("${adUrl}")
private String adUrl;
@Value("${rootDn}")
private String rootDn;
@Value("${searchFilter}")
private String searchFilter;
private final AuthenticationManagerBuilder auth;
private final SessionRepository sessionRepository;
@Autowired
public SecurityConfiguration(AuthenticationManagerBuilder auth, SessionRepository sessionRepository) {
this.auth = auth;
this.sessionRepository = sessionRepository;
}
@Override
public void configure(WebSecurity webSecurity) throws Exception
{
webSecurity
.ignoring()
// All of Spring Security will ignore the requests
.antMatchers("/static/**", "/api/web/logout")
.antMatchers(HttpMethod.POST, "/api/web/login");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() // Using JWT there is no need for CSRF-protection!
.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthorizationFilter(authenticationManagerBean(), sessionRepository));
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
ActiveDirectoryLdapAuthenticationProvider adProvider =
new ActiveDirectoryLdapAuthenticationProvider(adDomain, adUrl, rootDn);
adProvider.setConvertSubErrorCodesToExceptions(true);
adProvider.setUseAuthenticationRequestCredentials(true);
adProvider.setSearchFilter(searchFilter);
adProvider.setUserDetailsContextMapper(new InetOrgPersonContextMapper());
auth.authenticationProvider(adProvider);
return super.authenticationManagerBean();
}}
控制器方法如下所示
@RequestMapping(path = "/licenses", method = RequestMethod.GET)
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<?> getAllLicenses(@RequestParam("after") int pagenumber, @RequestParam("size") int pagesize
, @RequestParam("searchText") String searchText) {
List<LicenseDTO> result = ...
return new ResponseEntity<Object>(result, HttpStatus.OK);
}我很确定我错过了一些非常简单的东西,但我就是弄不明白是什么。
顺便说一句:如果请求许可证的用户具有ADMIN角色,则一切工作正常,因此问题不是真正的404。
发布于 2019-04-30 17:42:38
您需要在安全配置中定义exceptionHandling,如下所示。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() // Using JWT there is no need for CSRF-protection!
.authorizeRequests()
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(new AccessDeniedExceptionHandler())
.and()
.addFilter(new JwtAuthorizationFilter(authenticationManagerBean(), sessionRepository));
}您可以按如下方式定义AccessDeniedExceptionHandler类:
public class AccessDeniedExceptionHandler implements AccessDeniedHandler
{
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException ex) throws IOException, ServletException {
response.setStatus(HttpStatus.FORBIDDEN);
}
}发布于 2019-04-30 16:49:59
我终于找到了一个适合我的目的的解决方案。我不知道这是否是处理这个问题的最好方法,但只需添加一个ExceptionHandler就行了。在过滤器链内部的某个地方,当没有这样的处理程序时,403会变成404。也许我转储是为了阅读和理解文档,但我没有找到任何建议您必须这样做的东西。因此,也许我这样解决问题是错误的,但以下是成功的代码(这是一个非常基本的实现,应该随着时间的推移而改进):
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(Throwable.class)
@ResponseBody
public ResponseEntity<String> handleControllerException(Throwable ex) {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
if(ex instanceof AccessDeniedException) {
status = HttpStatus.FORBIDDEN;
}
return new ResponseEntity<>(ex.getMessage(), status);
}
}发布于 2020-08-23 23:52:36
可以在注释@EnableGlobalMethodSecurity(prePostEnabled=true)的帮助下启用全局方法安全性。它和@Preauthorize的组合将为您的控制器创建一个新的代理,并且它将丢失请求映射,这将导致404异常。
要处理这个问题,可以使用SecurityConfiguration类中的注释@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)。
还在another answer中提供了详细信息。
https://stackoverflow.com/questions/55905824
复制相似问题