【发布时间】:2017-05-28 09:13:16
【问题描述】:
我有一个使用 Spring 框架和 Spring MVC 来创建 REST 端点的 Web 应用程序。身份验证由容器使用 Java EE 安全性(特别是 Wildfly 9 中由 Active Directory 支持的安全领域)提供,并且从应用程序数据库加载角色。我有一个过滤器应用的请求包装器,以通过普通的 Servlet API 提供用户详细信息。
web.xml:
<web-app ... version="3.1">
<security-constraint>
<web-resource-collection>
<web-resource-name>Unauthenticated Resources</web-resource-name>
<url-pattern>/favicon.ico</url-pattern>
<url-pattern>/NoAccess.html</url-pattern>
<url-pattern>/login</url-pattern>
<url-pattern>/css/*</url-pattern>
<url-pattern>/font/*</url-pattern>
<url-pattern>/images/*</url-pattern>
<url-pattern>/js/*</url-pattern>
<url-pattern>/lib/*</url-pattern>
<url-pattern>/partials/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>All Resources</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>App Realm</realm-name>
<form-login-config>
<form-login-page>/Login.jsp</form-login-page>
<form-error-page>/NoAccess.html</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>*</role-name>
</security-role>
</web-app>
SecurityFilter.java
@WebFilter(urlPatterns = { "*" })
public class SecurityFilter implements Filter {
...
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Don't wrap unauthenticated requests
if (httpRequest.getRemoteUser() == null) {
chain.doFilter(httpRequest, httpResponse);
return;
}
Person user = this.personRepository.findByLogin(httpRequest.getRemoteUser());
if (user != null) {
List<String> roles = this.personRepository.getRoles(user.getId());
HttpServletRequest wrappedRequest = new RequestWrapper(httpRequest, user, roles);
chain.doFilter(wrappedRequest, httpResponse);
} else {
httpResponse.sendRedirect(httpRequest.getContextPath() + "/NoAccess.html");
}
}
}
身份验证有效,并且在控制器中,我可以执行 request.getUserPrincipal() 和 request.isUserInRole("SYSTEM_ADMIN") 并且它们正确返回。现在我想为应用程序添加授权。我想在我的控制器方法上使用 JSR-250 @RolesPermitted 注释应用授权规则;我不想在单独的配置文件/类中列出所有规则。控制器示例:
@RestController
@RequestMapping("/people")
public class PersonController {
...
@RolesAllowed({Role.SYSTEM_ADMIN, Role.DEPARTMENT_ADMIN, Role.SYSTEM_AUDITOR, Role.AUDITOR})
@RequestMapping
public List<Person> listPeople(HttpServletRequest request) {
return this.personRepository.getPeople();
}
}
当然,这本身没有任何作用,所以我添加了一个带有@EnableWebSecurity 和@EnableGlobalMethodSecurity(jsr250Enabled = true) 的配置类。现在,当我点击该资源时,我收到错误org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext。很公平,所以我按照https://gist.github.com/virgium03/86938e43219bc28632d0 的示例进行操作,但我不断收到相同的错误。似乎过滤器永远不会添加到过滤器链中。
我已经阅读了许多教程和 SO 帖子,但它们几乎都说了同样的话,并且对我不起作用。我一定缺少一些简单的东西——毕竟,Spring Security 的所有信息都可以用来做出授权决定。有可能(可能?)我在这里遗漏了一些简单的东西。非常感谢所有帮助!
编辑
我已将以下代码添加到我的 SecurityFilter 类中以填充 Spring 安全上下文。它有效,但我觉得这不是理想的解决方案。
List<GrantedAuthority> authorities = roles.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
PreAuthenticatedAuthenticationToken auth = new PreAuthenticatedAuthenticationToken(user, "", authorities);
auth.setDetails(new WebAuthenticationDetails(wrappedRequest));
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
【问题讨论】:
标签: java spring-mvc jakarta-ee spring-security