【发布时间】:2017-08-12 00:23:45
【问题描述】:
标题可能有点误导,可能会让你觉得这很简单,所以我会详细说明。
我有一组端点(REST 服务),我想在不使用 Spring 安全性提供的常规登录方式的情况下保护它们。通常您会首先瞄准登录端点(默认为 j_pring_security_check),进行身份验证,然后将请求与 JSESSIONID 一起发送到服务端点。
在这种情况下,我想在没有重定向的情况下工作。
我想从客户端直接将带有 API-Key 和 HMAC 的 Header 发送到服务端点,然后在服务器上根据这些参数对请求者进行身份验证,然后继续处理请求。我不想使用会话(类似于 BasicAuthenticationFilter 所做的)。
总而言之,我希望能够一次性验证和处理请求。
所以我创建了自己的过滤器:
public class HMACFilter extends BasicAuthenticationFilter {
private static final Logger LOGGER = Logger.getLogger(HMACFilter.class);
public static final String HMAC_SECURITY_HEADER_APIKEY_FIELD = "VU-API-Key";
public static final String HMAC_SECURITY_HEADER_HMAC_FIELD = "VU-HMAC";
public static final String HMAC_SECURITY_HEADER_TIMESTAMP_FIELD = "VU-Timestamp";
public static final String HMAC_SECURITY_URL_AFFILIATEID_FIELD = "affiliateid";
public HMACFilter() {
//super("/api_security");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
String headerApiKey = obtainApiKey(request);
String headerHmac = obtainHMACSignature(request);
String headerTimestamp = obtainRequestDate(request);
int requestAffiliateId = obtainAffiliateId(request);
String requestMessage = obtainMessage(request);
VUHMACCredentials credentials = new VUHMACCredentials();
if (headerHmac == null || headerApiKey == null || headerTimestamp == null) {
throw new AuthenticationServiceException("Authentication Headers cannot be null");
}
credentials.setApiKey(headerApiKey);
credentials.setHMACSignature(headerHmac);
credentials.setTimestamp(Long.valueOf(headerTimestamp));
VUCustomHMACAuthenticationToken authRequest = new VUCustomHMACAuthenticationToken(requestAffiliateId, credentials, requestMessage);
try{
Authentication authResult = this.getAuthenticationManager().authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authResult);
} catch (AuthenticationException var12) {
SecurityContextHolder.clearContext();
this.onUnsuccessfulAuthentication(request, response, var12);
return;
}
chain.doFilter(request, response);
}
还有security.xml:
<security:http entry-point-ref="apiAuthenticationEntryPoint" pattern="/rest/api/**">
<security:intercept-url pattern="/rest/api/**"
access="ROLE_APIUSER" />
<security:custom-filter position="FIRST"
ref="hmacFilter" />
</security:http>
<bean id="hmacFilter" class="com.vu.acs.edge.external.api.security.HMACFilter"
p:authenticationEntryPoint-ref="apiAuthenticationEntryPoint"
p:authenticationManager-ref="hmacAuthenticationManager"/>
<bean id="hmacAuthenticationManager" class="com.vu.acs.edge.external.spring.security.VUCustomHMACAuthenticationManager"
/>
这个 xmls 覆盖 j_spring_security_check url,并在每个匹配模式 /rest/api/** 的 URL 上进行身份验证
这里的问题是 Spring Security 正在验证并返回 200 RC,但没有调用其余服务。那么,如何使框架在身份验证后调用其余服务?我需要 SavedRequestAwareAuthenticationSuccessHandler 的功能,但不使用重定向,一切都应该通过来自客户端的一个请求来完成。
【问题讨论】:
标签: java rest spring-mvc authentication spring-security