我正在尝试使用基于 CXF 的肥皂服务安全地安装 Spring Boot 应用程序。我已经浏览了一千个论坛,但无法正常工作。
我做了不同的测试,我在下面评论:
如果我只启用具有基本身份验证的 cxf-rt-ws-security 级别的安全性,则应用程序可以工作,例如,当从 SOAPUI 调用时,它会验证基本身份验证 http 凭据。这里我为 cxf BasicAuthAuthorizationInterceptor 定义了一个拦截器
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-ws-security</artifactId> <version>3.4.0</version> </dependency>
package com.byl.arquetipo.config;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.cxf.binding.soap.interceptor.SoapHeaderInterceptor;
import org.apache.cxf.configuration.security.AuthorizationPolicy;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.transport.Conduit;
import org.apache.cxf.ws.addressing.EndpointReferenceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BasicAuthAuthorizationInterceptor extends SoapHeaderInterceptor {
/** La constante logger. */
private static final Logger logger = LoggerFactory.getLogger(BasicAuthAuthorizationInterceptor.class);
/** La variable users. */
Map<String, String> users = new HashMap<String, String>();
/**
* Obtiene users.
*
* @return users
*/
public Map<String, String> getUsers() {
return users;
}
/**
* Establece users.
*
* @param users
* users
*/
public void setUsers(Map<String, String> users) {
this.users = users;
}
/**
* {@inheritDoc}
*/
@Override
public void handleMessage(Message message) throws Fault {
AuthorizationPolicy policy = message.get(AuthorizationPolicy.class);
// If the policy is not set, the user did not specify credentials.
// 401 is sent to the client to indicate that authentication is required.
if (policy == null) {
sendErrorResponse(message, HttpURLConnection.HTTP_UNAUTHORIZED);
return;
}
String username = policy.getUserName();
String password = policy.getPassword();
// CHECK USERNAME AND PASSWORD
if (!checkLogin(username, password)) {
logger.error("handleMessage: Invalid username or password for user: " + policy.getUserName());
sendErrorResponse(message, HttpURLConnection.HTTP_FORBIDDEN);
}
}
/**
* Check login.
*
* @param username
* username
* @param password
* password
* @return <code>true</code>, si termina correctamente
*/
private boolean checkLogin(String username, String password) {
for (Map.Entry<String, String> item : users.entrySet()) {
if (item.getKey().equals(username) && password.equals(item.getValue())) {
return true;
}
}
return false;
}
/**
* Send error response.
*
* @param message
* message
* @param responseCode
* response code
*/
private void sendErrorResponse(Message message, int responseCode) {
Message outMessage = getOutMessage(message);
outMessage.put(Message.RESPONSE_CODE, responseCode);
// Set the response headers
@SuppressWarnings("unchecked")
Map<String, List<String>> responseHeaders = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS);
if (responseHeaders != null) {
responseHeaders.put("WWW-Authenticate", Arrays.asList(new String[] { "Basic realm=realm" }));
responseHeaders.put("Content-Length", Arrays.asList(new String[] { "0" }));
}
message.getInterceptorChain().abort();
try {
getConduit(message).prepare(outMessage);
close(outMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Obtiene out message.
*
* @param inMessage
* in message
* @return out message
*/
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;
}
/**
* Obtiene conduit.
*
* @param inMessage
* in message
* @return conduit
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private Conduit getConduit(Message inMessage) throws IOException {
Exchange exchange = inMessage.getExchange();
EndpointReferenceType target = exchange.get(EndpointReferenceType.class);
// Conduit conduit = exchange.getDestination().getBackChannel(inMessage, null, target);
Conduit conduit = exchange.getDestination().getBackChannel(inMessage);
exchange.setConduit(conduit);
return conduit;
}
/**
* Close.
*
* @param outMessage
* out message
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private void close(Message outMessage) throws IOException {
OutputStream os = outMessage.getContent(OutputStream.class);
os.flush();
os.close();
}
}
- 如果我此时启用 spring-boot-starter-security 它总是给我一个 401 并且我无法让它工作。另外通过启用 spring-boot-starter-security 我无法调试它以进入 BasicAuthAuthorizationInterceptor 拦截器
'
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
我必须为应用程序的其余部分启用 spring-boot-starter-security,因为我还为 spring 公开了 REST 服务。
有人可以指导我如何解决问题吗?