考慮這樣一個使用場景,假如要查看所有進(jìn)入weblogic上請求的(注意不是訪問某個特定web app的)一些請求頭是否設(shè)置,如果沒有設(shè)置則返回以定制的頁面.否則正常處理.
這么一個簡單的需求在Tomcat下是很容易實現(xiàn)的,但是在weblogic下就比較奢侈了.
你可能想到weblogic中:
1)weblogic.security.net.ConnectionFilter
但是在ConnectionFilter中得到的信息太少了,根本不能查看請求頭
2)提供IdentityAsserter Provider,實現(xiàn)weblogic.security.spi.IdentityAsserter
這個可以拿到看到你配置的特定的請求頭了,但是還是不能查看完整請求,也不能寫Response
weblogic9.1好像提供weblogic.security.spi.IdentityAsserterV2,這個類的assertIdentity()方法有個ContextHandler類,通過它可以訪問到
HttpServletRequest,HttpServletResponse了,但是為了啟用你的IdentityAsserter Provider,你必須在你要攔截的web應(yīng)用中配置安全屬性(web.xml)并且還得auth-method為CLIENT-CERT模式.
這種方式一般用來實現(xiàn)單點登陸.
那么,難道還有別的方法?
是的,下面介紹一種特別的方法(基于weblogic 7.1的,weblogic8.1也可以,但是要改動一點點)
weblogic domain的配置文件config.xml在<domain>元素下有一個<StartupClass>元素,用于設(shè)置一個容器啟動類
<StartupClass ClassName="com.yovn.labs.wls.startup.Startup"
FailureIsFatal="true" LoadBeforeAppDeployments="true"
Name="MyStartup Class" Targets="myserver"/>
意義一目了然,就不多說了.
那么,在com.yovn.labs.wls.startup.Startup中干什么呢?
先通過weblogic.socket.JVMSocketManager.java來看看Weblogic是怎么管理Socket的
package weblogic.socket;
import weblogic.com.ProtocolHandlerDCOM;
import weblogic.iiop.ProtocolHandlerIIOP;
import weblogic.iiop.ProtocolHandlerIIOPS;
import weblogic.ldap.ProtocolHandlerLDAP;
import weblogic.rjvm.Protocol;
import weblogic.rjvm.t3.ProtocolHandlerT3;
import weblogic.rjvm.t3.ProtocolHandlerT3S;
import weblogic.servlet.internal.ProtocolHandlerHTTP;
import weblogic.servlet.internal.ProtocolHandlerHTTPS;
import weblogic.utils.AssertionError;
public final class JVMSocketManager
{
private static final boolean DEBUG = false;
private static final ProtocolHandler discHandlers[];
public static final int numDiscProtocols;
private static final ProtocolHandler defHandlers[];
public static final int numDefProtocols;
public JVMSocketManager()
{
}
static ProtocolHandler[] getDefaultProtocolHandlers()
{
return defHandlers;
}
static ProtocolHandler[] getDiscriminatingProtocolHandlers()
{
return discHandlers;
}
public static int[] makePortArray(int i, int j, int k, int l, int i1, int j1, int k1)
{
int ai[] = new int[7];
ai[0] = i;
ai[1] = j;
ai[2] = k;
ai[3] = l;
ai[4] = i1;
ai[5] = j1;
ai[6] = k1;
return ai;
}
static
{
try
{
discHandlers = (new ProtocolHandler[] {
ProtocolHandlerT3S.theHandler(), ProtocolHandlerT3.theHandler(), ProtocolHandlerIIOPS.theHandler(), ProtocolHandlerIIOP.theHandler(), ProtocolHandlerDCOM.theHandler(), ProtocolHandlerLDAP.theHandler()
});
numDiscProtocols = discHandlers.length;
defHandlers = (new ProtocolHandler[] {
ProtocolHandlerHTTPS.theHandler(), ProtocolHandlerHTTP.theHandler()
});
numDefProtocols = defHandlers.length;
}
catch(Throwable throwable)
{
throw new AssertionError("Protocol registration failed", throwable);
}
}
}
很顯然,它的protocol handler是通過一個final 數(shù)組來管理,加入我在Startup類里修改defHandlers里的第二個元素,那么處理HTTP請求的protocol handler就可以被換掉了
來看我們的代碼:
package com.yovn.labs.wls.startup;
import java.lang.reflect.Field;
import weblogic.socket.JVMSocketManager;
import weblogic.socket.ProtocolHandler;
import com.yovn.labs.wls.protocol.ProtocolHandlerHTTP;
/**
* @author yovn
*
*/
public class Startup {
/**
* @param args
* @throws NoSuchFieldException
* @throws SecurityException
*/
public static void main(String[] args) throws Exception {
Field f=JVMSocketManager.class.getDeclaredField("defHandlers");
f.setAccessible(true);
ProtocolHandler[] handlers=(ProtocolHandler[])f.get(null);
System.err.println("[Startup]===================================================:Mystart up class!");
System.err.println("[Startup]===================================================:default http handler is "+handlers[1]+"!");
handlers[1]=ProtocolHandlerHTTP.theHandler();
System.err.println("[Startup]===================================================:now, http handler is "+handlers[1]+"!");
}
}
好,現(xiàn)在HTTP Protocol Handler換成我們的 com.yovn.labs.wls.protocol.ProtocolHandlerHTTP類了
接下來就看我們的handler代碼了
package com.yovn.labs.wls.protocol;
import java.io.IOException;
import java.net.ProtocolException;
import java.net.Socket;
//import weblogic.protocol.configuration.NetworkChannel;//在weblogic8.1中
import weblogic.rjvm.NetworkChannel;//在weblogic7.1中
import weblogic.socket.MuxableSocket;
import weblogic.socket.ProtocolHandler;
import weblogic.utils.io.Chunk;
public class ProtocolHandlerHTTP
implements ProtocolHandler
{
private static ProtocolHandler theOne = null;
protected static String PROTOCOL_NAME = "HTTP";
public ProtocolHandlerHTTP()
{
}
public static ProtocolHandler theHandler()
{
if(theOne == null)
synchronized(ProtocolHandlerHTTP.class)
{
if(theOne == null)
theOne = new ProtocolHandlerHTTP();
}
return theOne;
}
public int getHeaderLength()
{
return 0;
}
public String getProtocolName()
{
return PROTOCOL_NAME;
}
public boolean claimSocket(Chunk chunk, Socket socket)
throws IOException
{
return true;
}
public boolean canReadHeaders(byte abyte0[], int i)
{
return true;
}
public MuxableSocket createSocket(Chunk chunk, Socket socket, NetworkChannel networkchannel)
throws IOException
{
if(!networkchannel.isProtocolEnabled(2) && !networkchannel.isDefaultChannel())
{
throw new ProtocolException("HTTP is disabled");
} else
{
MuxableSocketHTTP muxablesockethttp = new MuxableSocketHTTP(chunk, socket, networkchannel);
return muxablesockethttp;
}
}
}
這段代碼在要求創(chuàng)建MuxableSocket時創(chuàng)建了一個com.yovn.labs.wls.protocol.MuxableSocketHTTP,這個類里面就是我們做一些有意義的事情的地方了
來看代碼:
package com.yovn.labs.wls.protocol;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.Socket;
import java.net.SocketException;
import weblogic.rjvm.NetworkChannel;
import weblogic.servlet.internal.RequestParser;
import weblogic.servlet.internal.ServletRequestImpl;
import weblogic.socket.MaxMessageSizeExceededException;
import weblogic.socket.MuxableSocket;
import weblogic.utils.io.Chunk;
/**
* @author yovn
*
*/
public class MuxableSocketHTTP implements MuxableSocket {
private final MuxableSocket delegate;//the internal implementation
private Field countF;
private Field bufF;
private Field sockF;
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#dispatch()
*/
public void dispatch() {
try {
byte[] buf=(byte[])bufF.get(delegate);
int count=countF.getInt(delegate);
ServletRequestImpl servletrequestimpl = new ServletRequestImpl();
RequestParser requestparser = new RequestParser(servletrequestimpl,buf, count);
if(requestparser.parse()<0)
{
Socket sock=(Socket)sockF.get(delegate);
OutputStream out=sock.getOutputStream();
sendError(out,500,"Internal error");
out.close();
return;
}
String accessV=servletrequestimpl.getHeader("access");
if(accessV==null)
{
Socket sock=(Socket)sockF.get(delegate);
OutputStream out=sock.getOutputStream();
sendMessage(out,"You have not set 'access' header");
out.close();
return;
}
// System.out.println("+================================request first Line:"+servletrequestimpl.getFirstLine()+",request:"+servletrequestimpl.getRequestURI());
} catch (Exception e) {
e.printStackTrace();
}
delegate.dispatch();
}
void sendMessage(OutputStream out,String msg) throws IOException
{
String s="HTTP/1.1 "+200+" OK\r\n\r\n";
out.write(s.getBytes());
out.write(msg.getBytes());
out.flush();
}
void sendError(OutputStream out,int code,String msg) throws IOException
{
String s="HTTP/1.1 "+code+" "+msg+"\r\n\r\n";
out.write(s.getBytes());
out.flush();
}
public MuxableSocketHTTP(Chunk chunk1, Socket socket, NetworkChannel networkchannel)
throws IOException
{
//create our delegation first
delegate=new weblogic.servlet.internal.MuxableSocketHTTP(chunk1,socket,networkchannel);
//initiate private fields
try {
countF=weblogic.servlet.internal.MuxableSocketHTTP.class.getDeclaredField("count");
bufF=weblogic.servlet.internal.MuxableSocketHTTP.class.getDeclaredField("buf");
sockF=weblogic.servlet.internal.MuxableSocketHTTP.class.getDeclaredField("sock");
sockF.setAccessible(true);
countF.setAccessible(true);
bufF.setAccessible(true);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#endOfStream()
*/
public void endOfStream() {
delegate.endOfStream();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getBuffer()
*/
public byte[] getBuffer() {
return delegate.getBuffer();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getBufferOffset()
*/
public int getBufferOffset() {
return delegate.getBufferOffset();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getCompleteMessageTimeoutMillis()
*/
public int getCompleteMessageTimeoutMillis() {
return delegate.getCompleteMessageTimeoutMillis();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getIdleTimeoutMillis()
*/
public int getIdleTimeoutMillis() {
return delegate.getIdleTimeoutMillis();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getMaxMessageSize()
*/
public int getMaxMessageSize() {
return delegate.getMaxMessageSize();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getRawSocket()
*/
public Socket getRawSocket() {
return delegate.getRawSocket();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getReRegisterMX()
*/
public MuxableSocket getReRegisterMX() {
return delegate.getReRegisterMX();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getSocket()
*/
public Socket getSocket() {
return delegate.getSocket();
}
public void ensureForceClose() {
delegate.ensureForceClose();
}
public boolean isClosed() {
return delegate.isClosed();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getSocketInputStream()
*/
public InputStream getSocketInputStream() {
return delegate.getSocketInputStream();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#hasException(java.lang.Throwable)
*/
public void hasException(Throwable arg0) {
delegate.hasException(arg0);
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#incrementBufferOffset(int)
*/
public void incrementBufferOffset(int arg0)
throws MaxMessageSizeExceededException {
delegate.incrementBufferOffset(arg0);
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#isMessageComplete()
*/
public boolean isMessageComplete() {
return delegate.isMessageComplete();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#setReRegisterMX(weblogic.socket.MuxableSocket)
*/
public void setReRegisterMX(MuxableSocket arg0) {
delegate.setReRegisterMX(arg0);
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#setSoTimeout(int)
*/
public void setSoTimeout(int arg0) throws SocketException {
delegate.setSoTimeout(arg0);
}
}
主體在dispatch()方法里,我們先創(chuàng)建weblogic內(nèi)部的MuxableSocketHttp作為我們真正的實現(xiàn),然后利用RequestParser,ServletRequestImpl來解析
HTTP請求,解析后就可以查看詳細(xì)的請求內(nèi)容了,我們簡單的檢查一下一個特定的request header是否設(shè)置如果沒有,則告知沒有設(shè)置,否則正常處理.
好了,把上面的程序編譯,打包,扔到你的weblogic domain下,修該domain的config.xml如本文開頭所示.把你打好的包,加入你的weblogic類路徑,啟動weblogic.
Ok,現(xiàn)在你在瀏覽器里隨便請求一個weblogic上的地址,你會看到如下頁面:
You have not set 'access' header
我們再來寫個測試程序,如下:
package com.yovn.labs.wls.test;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* @author yovn
*
*/
public class TestAccess {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
URL url=new URL("http://localhost:7001/console");
HttpURLConnection conn=( HttpURLConnection)url.openConnection();
conn.addRequestProperty("access", "pass");
InputStream in=conn.getInputStream();
int len=0;
ByteArrayOutputStream bao=new ByteArrayOutputStream(1024*4);
byte[] bytes=new byte[1024];
while((len=in.read(bytes))>0)
{
bao.write(bytes,0,len);
}
in.close();
conn.disconnect();
System.out.println(bao.toString());
}
}
由于這個程序設(shè)置了'access'請求頭,所打印出來內(nèi)容就是正常請求該地址所產(chǎn)生的內(nèi)容.
下載:
code and jar