拦截器可以在客户端,也可以在服务端添加。当客户端发起一个WebService请求时,在客户端会创建输出拦截器链(outinterceptor),服务端接收到客户端的后,会创建输入拦截器链(ininterceptor)。当服务端返回响应消息时,响应消息会经过服务端的输出拦截链,客户端接收到服务端的响应时,会创建输入拦截器链,响应消息先经过输入拦截器链处理。拦截器在服务端和客户端的作用如图所示。
注:上图来源于网络。
下面,我们以一个Header认证为例,来演示CXF的拦截器的使用。
1、客户端拦截器
public class ClientAuthorInterceptor extends AbstractPhaseInterceptor {
/**
* 客户端申请的token信息
*/
private String token;
public ClientAuthorInterceptor(String token) {
// 设置拦截器的时机,在发送请求到服务端之前进行拦截
super(Phase.PREPARE_SEND);
this.token = token;
}
@Override
public void handleMessage(SoapMessage soap) throws Fault {
// 在soap消息中添加认证头信息
List headers = soap.getHeaders();
Document doc = DOMUtils.createDocument();
Element auth = doc.createElement(AuthorHeader.HEADER_NAME);
Element token = doc.createElement(AuthorHeader.HEADER_TOKEN);
token.setTextContent(this.token);
auth.appendChild(token);
Header header = new SoapHeader(new QName(AuthorHeader.HEADER_NAME), auth);
headers.add(header);
}
}
注意:客户端是outinterceptor
2、服务端拦截器
下面,服务端对发送的消息进行拦截,并做认证
@Slf4j
@Component
public class AuthInterceptor extends AbstractPhaseInterceptor {
@Autowired
private AuthorizationRepository repository;
public AuthInterceptor() {
super(Phase.USER_LOGICAL);
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
Header header = message.getHeader(new QName("authrity"));
if(null == header){
log.warn("token没有认证通过!原因为:客户端请求中不存在认证的Header");
throw new Fault(new AuthenticationException("token没有认证通过!原因为:客户端请求中不存在认证的Header"));
}
Element ele = (Element) header.getObject();
if(null == ele){
log.warn("token没有认证通过!原因为:客户端请求中认证的Header无认证信息");
throw new Fault(new AuthenticationException("token没有认证通过!原因为:客户端请求中认证的Header无认证信息"));
}
Node node = ele.getFirstChild();
if(null == node){
log.warn("token没有认证通过!原因为:客户端请求中认证的Header无认证信息");
throw new Fault(new AuthenticationException("token没有认证通过!原因为:客户端请求中认证的Header无认证信息"));
}
String token = node.getTextContent();
if(null == token || token.isEmpty()){
log.warn("token没有认证通过!原因为:客户端请求中认证的Header无token信息");
throw new Fault(new AuthenticationException("token没有认证通过!原因为:客户端请求中认证的Header无token信息"));
}
Authorization auth = repository.findByToken(token);
if(null == auth){
log.warn("token没有认证通过!原因为:客户端请求中认证的token信息无效,请查看申请流程中的正确token信息");
throw new Fault(new AuthenticationException("token没有认证通过!原因为:客户端请求中认证的token信息无效,请查看申请流程中的正确token信息,流程申请地址:http://127.0.0.1:8080/email"));
}
log.info("客户端认证成功,token有效!");
}
}
注:服务端为ininterceptor
编写拦截器很简单,只需继承AbstractPhaseInterceptor类并实现handleMessage即可。
3、spring boot配置拦截器,并发布服务
@Configuration
public class WebserviceConfig {
@Autowired
private EmailService emailService;
@Autowired
private AuthInterceptor interceptor;
@Autowired
private ValidateInterceptor validateInterceptor;
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
/**
* attention:
* Details:发布WebService服务
* @author chhliu
* 创建时间:2017年5月22日 上午11:30:08
* @return
* Endpoint
*/
@Bean
public Endpoint endpoint() {
EndpointImpl endPoint = new EndpointImpl(springBus(), emailService);
endPoint.publish("/eamil");
endPoint.getInInterceptors().add(interceptor); // 添加Header认证拦截器
endPoint.getInInterceptors().add(validateInterceptor);// 添加消息格式校验拦截器
return endPoint;
}
}
4、拦截器的Phase
Phase用来控制拦截器的工作时机,目前CXF支持的Phase如下:
public static final String SETUP = "setup";// 设置阶段
public static final String SETUP_ENDING = "setup-ending"; // 设置完之后
public static final String PRE_LOGICAL = "pre-logical";// 程序对象编码
public static final String PRE_LOGICAL_ENDING = "pre-logical-ending";
public static final String USER_LOGICAL = "user-logical";
public static final String USER_LOGICAL_ENDING = "user-logical-ending";
public static final String POST_LOGICAL = "post-logical";
public static final String POST_LOGICAL_ENDING = "post-logical-ending";
public static final String PRE_MARSHAL = "pre-marshal";
public static final String MARSHAL = "marshal";
public static final String POST_MARSHAL = "post-marshal";
public static final String MARSHAL_ENDING = "marshal-ending";
public static final String PRE_PROTOCOL = "pre-protocol";
public static final String PRE_PROTOCOL_FRONTEND = "pre-protocol-frontend";
public static final String PRE_PROTOCOL_ENDING = "pre-protocol-ending";
public static final String USER_PROTOCOL = "user-protocol";
public static final String USER_PROTOCOL_ENDING = "user-protocol-ending";
public static final String POST_PROTOCOL = "post-protocol";
public static final String POST_PROTOCOL_ENDING = "post-protocol-ending";
public static final String PREPARE_SEND = "prepare-send";
public static final String PREPARE_SEND_ENDING = "prepare-send-ending";
public static final String PRE_STREAM = "pre-stream";
public static final String PRE_STREAM_ENDING = "pre-stream-ending";
public static final String USER_STREAM = "user-stream";
public static final String USER_STREAM_ENDING = "user-stream-ending";
public static final String POST_STREAM = "post-stream";
public static final String POST_STREAM_ENDING = "post-stream-ending";
public static final String WRITE = "write";
public static final String WRITE_ENDING = "write-ending";
public static final String SEND = "send";
public static final String SEND_ENDING = "send-ending";
public static final String RECEIVE = "receive"; // 接收阶段,传输层处理
public static final String READ = "read";// SOAPHeader读取
public static final String PROTOCOL = "protocol";// 协议处理阶段,例如JAX-WS的Handler处理
public static final String PRE_UNMARSHAL = "pre-unmarshal";// SOAP请求解码之前
public static final String UNMARSHAL = "unmarshal";// SOAP请求解码阶段
public static final String POST_UNMARSHAL = "post-unmarshal"; // SOAP请求解码之后
public static final String PRE_INVOKE = "pre-invoke"; // 调用业务处理之前进入该阶段
public static final String INVOKE = "invoke"; // 调用业务阶段
public static final String POST_INVOKE = "post-invoke";// 业务调用之后
以下是ininterceptor定义的Phase
Phase |
Functions |
---|---|
RECEIVE |
Transport level processing |
(PRE/USER/POST)_STREAM |
Stream level processing/transformations |
READ |
This is where header reading typically occurs. |
(PRE/USER/POST)_PROTOCOL |
Protocol processing, such as JAX-WS SOAP handlers |
UNMARSHAL |
Unmarshalling of the request |
(PRE/USER/POST)_LOGICAL |
Processing of the umarshalled request |
PRE_INVOKE |
Pre invocation actions |
INVOKE |
Invocation of the service |
POST_INVOKE |
Invocation of the outgoing chain if there is one |
On the outgoing chain there are the following phases:
Phase |
Functions |
---|---|
SETUP |
Any set up for the following phases |
(PRE/USER/POST)_LOGICAL |
Processing of objects about to marshalled |
PREPARE_SEND |
Opening of the connection |
PRE_STREAM |
|
PRE_PROTOCOL |
Misc protocol actions. |
WRITE |
Writing of the protocol message, such as the SOAP Envelope. |
MARSHAL |
Marshalling of the objects |
(USER/POST)_PROTOCOL |
Processing of the protocol message. |
(USER/POST)_STREAM |
Processing of the byte level message |
SEND |
|
通过上面的示例,可以发现,CXF的拦截器可以为我们实现很多的附加功能。