You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kerberos认证实现疑问:仅返回Negotiate头能否获取Kerberos票据?

Kerberos认证问题排查与无Web依赖实现方案

为何拿到的是NTLM而非Kerberos票据?

仅返回WWW-Authenticate: Negotiate头的401响应没法强制Windows客户端选Kerberos——Negotiate是让客户端自行在Kerberos和NTLM二选一,出现NTLM大概率是以下环节出了问题:

  • AD服务器端:
    • 没给应用服务器创建正确的服务主体名称(SPN),或者SPN没绑定到应用服务器的服务账户(得用setspn -S HTTP/你的应用服务器FQDN@域名.COM 域\服务账户命令配置)
    • 应用服务器的服务账户没有委派权限,或者SPN重复绑定
  • Windows客户端:
    • 没把应用服务器的FQDN加入本地Intranet区域(IE/Edge在Internet选项里配,Chrome会继承这个设置)
    • Kerberos缓存有无效票据,可跑klist purge命令清空
    • 客户端解析应用服务器FQDN到的IP不对,导致Kerberos请求失败,降级用NTLM
  • 应用服务器端:只返回Negotiate头只是触发协商,但客户端发Kerberos令牌后,应用得用GSS-API/SPNEGO解析验证,不然客户端会 fallback到NTLM

必须用SPNEGO或GSS-API吗?

对,必须靠SPNEGO或GSS-API处理Kerberos令牌。Negotiate头只是让客户端发起认证协商,但Kerberos令牌的解析、验证(比如校验签名、取用户身份)都得依赖GSS-API(Java里是org.ietf.jgss包)或者基于它封装的SPNEGO实现,没这步根本拿不到有效的Kerberos身份信息。

无Spring Security Web依赖的Kerberos实现步骤

既然只能用AbstractPhaseInterceptor和InterceptionProvider,按下面的步骤来:

  1. 配Kerberos基础环境:
    • 在应用服务器放正确的krb5.conf(Linux)或krb5.ini(Windows),示例:
      [libdefaults]
        default_realm = YOURDOMAIN.COM
        dns_lookup_kdc = true
        dns_lookup_realm = true
      [realms]
        YOURDOMAIN.COM = {
          kdc = dc.yourdomain.com
          admin_server = dc.yourdomain.com
        }
      [domain_realm]
        .yourdomain.com = YOURDOMAIN.COM
        yourdomain.com = YOURDOMAIN.COM
      
    • 给JVM加参数指定配置文件路径:-Djava.security.krb5.conf=/你的路径/krb5.conf
  2. 写Kerberos认证拦截器:
    • 继承AbstractPhaseInterceptor,在拦截逻辑里处理请求头:
      • 检查请求有没有带Authorization: Negotiate <token>头
      • 没带的话,返回401并设置WWW-Authenticate: Negotiate头
      • 带了令牌就用GSS-API解析,核心代码示例:
        GSSManager manager = GSSManager.getInstance();
        GSSName serverName = manager.createName("HTTP/你的应用服务器FQDN@YOURDOMAIN.COM", GSSName.NT_HOSTBASED_SERVICE);
        GSSContext context = manager.createContext(serverName, null, null, GSSContext.DEFAULT_LIFETIME);
        byte[] token = Base64.getDecoder().decode(authToken);
        byte[] responseToken = context.acceptSecContext(token, 0, token.length);
        // 拿到认证用户的身份
        String userName = context.getSrcName().toString();
        context.dispose();
        
    • 把解析出的用户身份传给自定义认证逻辑,和现有的Basic、LDAP认证提供者整合
  3. 绑定SPN并生成keytab:
    • 在AD服务器用域管理员权限执行:setspn -S HTTP/你的应用服务器FQDN YOURDOMAIN\应用服务账户,确保SPN唯一
    • 生成keytab文件:ktpass /princ HTTP/你的应用服务器FQDN@YOURDOMAIN.COM /mapuser YOURDOMAIN\应用服务账户 /pass * /out app-server.keytab /ptype KRB5_NT_PRINCIPAL /crypto AES256-SHA1
    • 给JVM加参数指定keytab和登录配置:-Djavax.security.auth.useSubjectCredsOnly=false -Djava.security.auth.login.config=/你的路径/jaas.conf
    • jaas.conf示例:
      Krb5Login {
        com.sun.security.auth.module.Krb5LoginModule required
        useKeyTab=true
        keyTab="/你的路径/app-server.keytab"
        principal="HTTP/你的应用服务器FQDN@YOURDOMAIN.COM"
        storeKey=true
        useTicketCache=false;
      };
      

之前配置无效的常见原因

  • SPN和keytab配置不对,导致应用服务器没法验证Kerberos令牌
  • krb5.conf/ini配置错误,比如KDC地址、域名称大小写不匹配(Kerberos对大小写敏感)
  • 客户端没把应用服务器加入Intranet区域,浏览器默认不发Kerberos令牌
  • 应用端没实现Kerberos令牌的解析逻辑,光返回Negotiate头完不成完整认证流程

内容的提问来源于stack exchange,提问作者Olga D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 19:05:08