dianping / cat

CAT 作为服务端项目基础组件,提供了 Java, C/C++, Node.js, Python, Go 等多语言客户端,已经在美团点评的基础架构中间件框架(MVC框架,RPC框架,数据库框架,缓存框架等,消息队列,配置系统等)深度集成,为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。
Apache License 2.0
18.69k stars 5.43k forks source link

关于登录 #2193

Closed Jacksonary closed 2 years ago

Jacksonary commented 2 years ago

背景:自己 K8S 集群内部署后,登录非常奇怪,一样的凭证怎么登都不跳转,中间换一次其他的凭证再换回来可以登录,登录成功后点击需要授权的页面,系统再次跳到登录页面。

登录失败

Jacksonary commented 2 years ago

后端也没有异常日志

Jacksonary commented 2 years ago

多个代理 Pod,在这种情况下 Cat 的Token 实现机制有点问题,在获取客户端 ip 时不能直接使用 getRemoteAddress,使用下面的工具类获取重新编译打包即可。

package com.dianping.cat.util;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;

/**
 * @author jacks
 * @date 2022/4/2
 */
public class ServletRequestUtils {

    private static final String UNKNOWN = "unknown";
    private static final String X_FORWARDED_FOR = "x-forwarded-for";
    private static final String PROXY_CLIENT_IP = "Proxy-Client-IP";
    private static final String WL_Proxy_Client_IP = "WL-Proxy-Client-IP";

    public static String getRemoteAddress(HttpServletRequest request) {
        if (request == null) {
            return UNKNOWN;
        }

        String ip = request.getHeader(X_FORWARDED_FOR);
        if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(PROXY_CLIENT_IP);
        }
        if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(WL_Proxy_Client_IP);
        }
        if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
bambooHouse commented 2 years ago

@jacksonary 关于如何获取client ip,我查阅了一些资料,参考下面链接里面matin的回答还有最高票回答,我也倾向于认为 只能信赖"x-forwarded-for"(只有当代理被正确配置,可以被信任的情况下)和getRemoteAddr() https://stackoverflow.com/questions/16558869/getting-ip-address-of-client#:~:text=This%20is%20so,%E2%80%93%C2%A0

CAT既有代码也是这样处理的 https://github.com/dianping/cat/blob/master/lib/java/src/main/java/com/dianping/cat/servlet/CatFilter.java#:~:text=private%20void%20logRequestClientInfo(HttpServletRequest%20req%2C%20String%20type)%20%7B

如有不对,请多指教

Jacksonary commented 2 years ago

@bambooHouse 同意你的说法,其实包括 x-forwarded-for 都不一定真实,但目前 K8S 内部 ingress controller 内部的 Daemon 部署方式决定了我们不能通过上面的方式获取一个固定的 clientIp, 所以 cat 这种 token 算法在这样的场景下无法进行成功验证。不过可以理解,对于 K8S 部署方式官方还没有做适配,在单节点 nginx (可能前置SLB) 可能没有问题