解决问题:
1. 在认证之前做个过滤InternalServerTokenFilter。如没有带内部token, 就不继续认证controller的处理了
2. 过滤拿走request 的body后,controller不可再次消费,此时需要重新生成一个InternalServerTokenRequestWrapper, 可永久保存request body
3. 过滤器需要捕捉异常,进行特殊处理返回给前端 InternalServerTokenFilter::exceptionHandle
public class InternalServerTokenFilter extends GenericFilterBean {
private static final Logger logger = LoggerFactory
.getLogger(InternalServerTokenFilter.class);
private InternalServerUiConf internalServerUiConf;
private InternalTokenService internalTokenService;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws ServletException, IOException {
if (false == internalServerUiConf.getEnable()) {
// Disable: do nothing
chain.doFilter(request, response);
return;
}
// Enable: validate it.
// Consume input stream of request and wrap a new request for control
// consumption.
// Because input stream can be consumed only once.
InternalServerTokenRequestWrapper requestWrapper = new InternalServerTokenRequestWrapper(
(HttpServletRequest) request);
String body = requestWrapper.getBody();
try {
internalTokenService.validate(body);
} catch (InvalidInternalTokenException e) {
exceptionHandle((HttpServletRequest) request,
(HttpServletResponse) response, e);
return;
} catch (Exception e) {
logger.error("internal token filter exception. ", e.getMessage());
throw new ServletException(e);
}
// Pass through
chain.doFilter((ServletRequest) requestWrapper, response);
}
private void exceptionHandle(HttpServletRequest request,
HttpServletResponse response, InvalidInternalTokenException e)
throws IOException {
response.setStatus(HttpStatus.FORBIDDEN.value());
InternalTokenResponse internalTokenResponse = new InternalTokenResponse(
e.getCode(), e.getMessage());
JSONObject objResponse = JSONObject.fromObject(internalTokenResponse);
String strResponse = objResponse.toString();
PrintWriter outBody = response.getWriter();
outBody.println(strResponse);
outBody.flush();
outBody.close();
}
public InternalTokenService getInternalTokenService() {
return internalTokenService;
}
public void setInternalTokenService(
InternalTokenService internalTokenService) {
this.internalTokenService = internalTokenService;
}
public InternalServerUiConf getInternalServerUiConf() {
return internalServerUiConf;
}
public void setInternalServerUiConf(
InternalServerUiConf internalServerUiConf) {
this.internalServerUiConf = internalServerUiConf;
}
}
package com.hp.ccue.identity.utilities;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class InternalServerTokenRequestWrapper
extends
HttpServletRequestWrapper {
private final String body;
public InternalServerTokenRequestWrapper(HttpServletRequest request)
throws IOException {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));
char[] charBuffer = new char[1024];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException e) {
throw e;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
throw e;
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
<bean id="internalServerTokenFilter" class="com.hp.ccue.identity.filter.InternalServerTokenFilter">
<property name="internalServerUiConf" ref="internalServerUiConf"/>
<property name="internalTokenService" ref="internalTokenService"/>
</bean>
<security:http pattern="/../v0/.." use-expressions="true" auto-config="false">
<security:csrf disabled="true" />
<security:custom-filter ref="internalServerTokenFilter" />
<security:http-basic />
</security:http>