websocket中獲取客戶端通信的真實IP


一些場景中,我們要對websocket客戶端的ip進行校驗,如果是黑名單,或者不被允許的則不應該讓他訪問業務系統。

筆者本地使用了兩個Websocket技術原型,一個基於Netty封裝的Websocket框架:YeautyYE/netty-websocket-spring-boot-starter

另外一個是基於JSR-356 Java Api for websocket實現的框架,實現的客戶端很多,比如tomcat,spring也有對應的支持。

 

 表達式獲得方法

 

 

 因為使用Ognl解析對象時,會把對象數據放入一棵樹,在任意調試窗口監控可以查看到類及屬性的層次關系。

比如查詢Ip地址,我們這里選擇的樹路徑是

#root->channel->remoteAddress

他返回的對象時InetSocketAddress的實例,得到這個對象后,你可以調用

.getAddress().getHostAddress()
方法獲得最終的ip真實地址,當然你也可以使用其他表達式來獲得
#root.channel.remoteAddress.holder.addr.holder.hostName
#root.channel.remoteAddress.holder.addr.hostName

這些表達式需要你自己去評估計算。

netty-websocket-spring-boot-starter

封裝代碼如下:

import lombok.extern.slf4j.Slf4j;
import ognl.DefaultMemberAccess;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.yeauty.pojo.Session;


@Slf4j
public final class NettyWebsocketHelper {
    private NettyWebsocketHelper() {
    }

    private static OgnlContext context = new OgnlContext();

    /**
     * set DefaultMemberAccess with allowed access into the context
     */
    static {
        context.setMemberAccess(new DefaultMemberAccess(true));
    }


    public static String getRemoteAddress(final Session session) {
        //.getAddress().getHostAddress()
        //.holder.addr.hostName
        //.holder.addr.holder.address
        //.holder.addr.holder.hostName
        //return (String) eval(session,"#root.channel.remoteAddress");
        return eval(session, "#root.channel.remoteAddress.getAddress().getHostAddress()", String.class);
    }

    public static <T> T eval(final Object source, final String expression, Class<T> targetClass) {
        try {
            return (T) Ognl.getValue(expression, context, source);
        } catch (OgnlException e) {
            log.error("評估表達式出錯:{}", e);
            throw new IllegalAccessError("expression invalid");
        }
    }

    public static Object eval(final Object source, final String expression) {
        Object value = null;
        try {
            value = Ognl.getValue(expression, context, source);
            log.info("return value :{}, class.name:{}", value, value.getClass().getName());
        } catch (OgnlException e) {
            log.error("評估表達式出錯:{}", e);
        }
        return value;
    }
}

使用方法:

    /***
     * 登錄ws服務器
     * @param session
     * @param appId
     * @param apiKey
     * @throws InterruptedException
     */
    private void onLogin(Session session, String appId, String apiKey) {

        String remoteAddress = NettyWebsocketHelper.getRemoteAddress(session);

        ApiService service = apiService.getService(appId, apiKey);

        if (Objects.isNull(service)) {
            session.sendText("appid無效");
            session.close();
            return;
        }

        final String serviceType = service.getServiceType();

        final Integer serviceId = service.getId();

        log.info("遠程IP:{}正在嘗試登錄到api服務器", remoteAddress);

        if (!checkWhiteList(serviceId, remoteAddress)) {
            session.sendText("禁止調用API接口的IP:".concat(remoteAddress));
            session.close();
            return;
        }
}

調用結果

2020-1-15日更新:

參考來源:https://stackoverflow.com/questions/22690907/client-socket-get-ip-java

/***
 * 登錄ws服務器
 * @param session
 * @param appId
 * @param apiKey
 * @throws InterruptedException
 */
private void onLogin(Session session, String appId, String apiKey) {
    String ip = resolveRemoteIp(session.remoteAddress());

    log.info("遠程IP地址:{}",ip);
}

String resolveRemoteIp(SocketAddress socketAddress)
{
    if (socketAddress instanceof InetSocketAddress) {
        InetAddress inetAddress = ((InetSocketAddress)socketAddress).getAddress();
        if (inetAddress instanceof Inet4Address) {
            log.info("IPv4:{}",inetAddress);
            return inetAddress.getHostAddress();
        }else if (inetAddress instanceof Inet6Address) {
            log.info("IPv6:{}",inetAddress);
        }else {
            log.error("Not an IP address.");
            return null;
        }
    } else {
        log.error("Not an internet protocol socket.");
    }
    return null;
}

 

JSR356

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM