Hak*_*man 4 java web-services cxf jax-rs
我试图通过使其中一个方法需要HTTP基本身份验证来确保我的Web服务安全.为了做到这一点,我实现了一个自定义的Interceptor调用LoginInterceptor,它检查请求的URL,如果它对应于一个被调用的方法open,它会检查消息头是否有用户名和密码.
如果标头中没有验证字段,则响应代码设置为HTTP_UNAUTHORIZED,如果用户名或密码不正确,则将响应代码设置为HTTP_FORBIDDEN.这是代码:
public LoginInterceptor() {
super(Phase.RECEIVE);
addAfter(RequestInterceptor.class.getName()); //another custom interceptor, for some simple redirections.
}
public void handleMessage(Message message) throws Fault {
String requestURI = message.get(Message.REQUEST_URI).toString();
String methodKeyword = requestURI.substring("localhost".length()+1).split("/")[0];
if(methodKeyword.equals("open")) {
AuthorizationPolicy policy = message.get(AuthorizationPolicy.class);
if(policy == null) {
sendErrorResponse(message, HttpURLConnection.HTTP_UNAUTHORIZED);
return;
}
//userPasswords is a hashmap of usernames and passwords.
String realPassword = userPasswords.get(policy.getUserName());
if (realPassword == null || !realPassword.equals(policy.getPassword())) {
sendErrorResponse(message, HttpURLConnection.HTTP_FORBIDDEN);
}
}
}
//This is where the response code is set, and this is where I'd like to write the response message.
private void sendErrorResponse(Message message, int responseCode) {
Message outMessage = getOutMessage(message);
outMessage.put(Message.RESPONSE_CODE, responseCode);
// Set the response headers
Map responseHeaders = (Map) message.get(Message.PROTOCOL_HEADERS);
if (responseHeaders != null) {
responseHeaders.put("Content-Type", Arrays.asList("text/html"));
responseHeaders.put("Content-Length", Arrays.asList(String.valueOf("0")));
}
message.getInterceptorChain().abort();
try {
getConduit(message).prepare(outMessage);
close(outMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
private Message getOutMessage(Message inMessage) {
Exchange exchange = inMessage.getExchange();
Message outMessage = exchange.getOutMessage();
if (outMessage == null) {
Endpoint endpoint = exchange.get(Endpoint.class);
outMessage = endpoint.getBinding().createMessage();
exchange.setOutMessage(outMessage);
}
outMessage.putAll(inMessage);
return outMessage;
}
//Not actually sure what this does. Copied from a tutorial online. Any explanation is welcome
private Conduit getConduit(Message inMessage) throws IOException {
Exchange exchange = inMessage.getExchange();
Conduit conduit = exchange.getDestination().getBackChannel(inMessage);
exchange.setConduit(conduit);
return conduit;
}
private void close(Message outMessage) throws IOException {
OutputStream os = outMessage.getContent(OutputStream.class);
os.flush();
os.close();
}
Run Code Online (Sandbox Code Playgroud)
这工作正常,但是,我想在响应中返回一条消息,例如"用户名或密码不正确".我已尝试从sendErrorResponse方法中做:
outMessage.setContent(String.class, "incorrect username or password")
我将内容长度设置为"incorrect username or password".length().这不起作用,我想因为Apache CXF消息使用InputStreams和OutputStreams.
所以我尝试过:
OutputStream os = outMessage.getContent(OutputStream.class);
try {
os.write("incorrect username or password".getBytes() );
outMessage.setContent(OutputStream.class, os);
} catch (IOException e) {
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
这也不起作用.当用调试器逐句通过,我注意到,os就是null当邮递员测试,我得到:
无法获得任何响应这似乎是连接到的错误
http://localhost:9090/launcher/open.响应状态为0.有关何时发生此更多详细信息,请查看W3C XMLHttpRequest Level 2规范.
在Chrome中按ctrl + shif + c(打开开发工具),然后检查网络标签,我看到:
"ERR_CONTENT_LENGTH_MISMATCH"
Run Code Online (Sandbox Code Playgroud)
我已经尝试过使用XMLStreamWriter,但是没有更好的.
问题:
我可以返回正确的响应代码(401 Unauthorized和403 forbidden),但是如何在响应正文中返回消息?
我是否需要专门扩展特定的OutInterceptor,如JASRXOutInterceptor才能修改消息内容?
我之前尝试过使用JAASInterceptor,但我没有设法让它工作.有人可以告诉我如何以这种方式实现它,如果这在某种程度上更容易吗?
我也可以像这样抛出一个错误:throw new Fault("incorrect username or password", Logger.getGlobal());但是HTTP响应代码将是500.我宁愿返回正确的401或403响应.
注意:
现在我仍在使用HTTP作为传输层.解决这个问题后,我将更改为HTTPS.
基本上,我想要做的是返回错误,HTTP响应代码为401(未授权)或403(禁止)而不是500(服务器错误).事实证明Apache CXF提供了一种简单的方法,使用Fault.setStatusCode(int) method,正如我从Stack Overflow上的这个问题中发现的:如何在Apache CXF中抛出403错误 - Java
所以这就是我的handleMessage方法现在的样子:
public void handleMessage(Message message) throws Fault {
String requestURI = message.get(Message.REQUEST_URI).toString();
String methodKeyword = requestURI.substring("localhost".length()+1).split("/")[0];
if(methodKeyword.equals("open")) {
AuthorizationPolicy policy = message.get(AuthorizationPolicy.class);
if(policy == null) {
Fault fault = new Fault("incorrect username or password", Logger.getGlobal());
fault.setStatusCode(401);
throw fault;
}
String realPassword = userPasswords.get(policy.getUserName());
if (realPassword == null || !realPassword.equals(policy.getPassword())) {
Fault fault = new Fault("incorrect username or password", Logger.getGlobal());
fault.setStatusCode(403);
throw fault;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我删除了其他方法,它们是不必要的.
| 归档时间: |
|
| 查看次数: |
3193 次 |
| 最近记录: |