spring boot-实现WebService(CXF实现)的拦截器(Interceptor)

拦截器(Interceptor)是CXF功能最主要的扩展点,可以在不对核心模块进行修改的情况下,动态添加很多功能。拦截器和JAX-WS Handler、Filter的功能类似,当服务被调用时,就会创建一个拦截器链(Interceptor Chain),拦截器链在服务输入(IN)或输出(OUT)阶段实现附加功能。

拦截器可以在客户端,也可以在服务端添加。当客户端发起一个WebService请求时,在客户端会创建输出拦截器链(outinterceptor),服务端接收到客户端的后,会创建输入拦截器链(ininterceptor)。当服务端返回响应消息时,响应消息会经过服务端的输出拦截链,客户端接收到服务端的响应时,会创建输入拦截器链,响应消息先经过输入拦截器链处理。拦截器在服务端和客户端的作用如图所示。

spring boot-实现WebService(CXF实现)的拦截器(Interceptor)_第1张图片

注:上图来源于网络。

下面,我们以一个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

以下是outintercptor定义的Phase

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

 

在SEND Phase后,有一堆以*_ENDING Phase以及与之对应的Phase,例如SEND和SEND_ENDING,这类以ENDING结尾的Phase允许清理和关闭与之对应的Phase打开或启动的任何资源。

通过上面的示例,可以发现,CXF的拦截器可以为我们实现很多的附加功能。

你可能感兴趣的:(spring,boot,spring,cloud微服务)