经过几天的努力(寻找类似问题,反复试验),我很想放弃...
所以问题是我有一个使用Spring Security和JWT进行身份验证的基于Spring Boot的REST服务。现在,我想确保某些方法只能由授权人员使用@PreAuthorize
注释来调用。
这似乎部分有用,因为与其调用Spring返回404的方法,还不如调用403。
我已经阅读了SO-question,并尝试了此处给出的答案,但没有帮助。我已经按照其他地方的建议将@EnableGlobalMethodSecurity(prePostEnabled = true)
-注释从我的SecurityConfiguration移到了Application类,但这仍然行不通。
我的安全配置如下:
@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。
答案 0 :(得分:2)
您需要按如下所示在安全性配置中定义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);
}
}
答案 1 :(得分:0)
我终于找到了适合自己目的的解决方案。我不知道这是否是解决此问题的最佳方法,但是仅添加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);
}
}
答案 2 :(得分:0)
可以在注释@EnableGlobalMethodSecurity(prePostEnabled=true)
的帮助下启用全局方法安全性。此和@Preauthorize
的组合将为您的控制器创建一个新的代理,并将释放请求映射,这将导致404异常。
要处理此问题,您可以使用@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
类中的注释SecurityConfiguration
。
还在another answer中提供了详细信息。