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

ASP.NET Core 2中基于Rediris OpenID 2.0的RP认证问题求助

解决ASP.NET Core 2对接Rediris OpenID 2.0身份服务器的认证请求问题

首先要明确:ASP.NET Core的AddOpenIdConnect中间件是为OpenID Connect 1.0设计的,而Rediris的PAPI框架遵循的是OpenID Authentication 2.0规范,这两个协议核心逻辑不兼容,所以你之前的配置无效是必然的。我们需要手动实现OpenID 2.0的认证流程,才能匹配Rediris的要求。

核心解决方案步骤

1. 移除无效的AddOpenIdConnect配置

直接删掉Startup里的AddOpenIdConnect代码块,它无法生成符合OpenID 2.0要求的认证参数,继续使用只会增加不必要的调试成本。

2. 手动构造OpenID 2.0认证请求

你需要生成一个自动提交的POST表单,向Rediris的端点发送指定参数。在你的登录控制器动作里,完成以下操作:

  • 生成唯一nonce(防止重放攻击)
  • 取出之前通过Smart Mode获取的assoc_handle、mac_key等关联信息
  • 构造包含所有必填参数的POST表单

示例控制器代码:

public IActionResult Login()
{
    // 替换为你实际获取的关联句柄
    var assocHandle = "{HMAC-SHA1}{5a3294ef}{A8uNlg==}";
    var nonce = Guid.NewGuid().ToString();
    // 生成符合要求的return_to地址,确保在realm范围内
    var returnUrl = Url.Action("LoginCallback", "Account", new { nonce = nonce }, Request.Scheme);
    var realm = $"{Request.Scheme}://{Request.Host}/";

    // 构建OpenID 2.0标准参数
    var formParams = new Dictionary<string, string>
    {
        {"openid.ns", "http://specs.openid.net/auth/2.0"},
        {"openid.ns.sreg", "http://openid.net/extensions/sreg/1.1"},
        {"openid.sreg.required", "nickname,email"},
        {"openid.sreg.optional", "fullname"},
        {"openid.realm", realm},
        {"openid.mode", "checkid_setup"},
        {"openid.return_to", returnUrl},
        {"openid.identity", "http://specs.openid.net/auth/2.0/identifier_select"},
        {"openid.claimed_id", "http://yo.rediris.es/"},
        {"openid.assoc_handle", assocHandle}
    };

    // 生成自动提交的HTML表单,让浏览器自动发送POST请求
    var html = $@"
    <html>
        <body onload='document.forms[0].submit()'>
            <form method='post' action='https://yo.rediris.es/papoid-server.php'>
                {string.Join("\n", formParams.Select(kv => $"<input type='hidden' name='{kv.Key}' value='{HttpUtility.HtmlEncode(kv.Value)}' />"))}
            </form>
        </body>
    </html>";

    return Content(html, "text/html");
}

3. 处理回调(return_to端点)

创建LoginCallback动作,接收Rediris返回的响应,完成签名验证和用户信息提取:

[HttpGet]
public async Task<IActionResult> LoginCallback(string nonce)
{
    // 提取所有请求参数
    var requestParams = Request.Query.ToDictionary(kv => kv.Key, kv => kv.Value.ToString());

    // 1. 检查是否为认证成功响应
    if (requestParams.TryGetValue("openid.mode", out var mode) && mode != "id_res")
    {
        // 处理取消或错误情况
        return RedirectToAction("Login");
    }

    // 2. 验证nonce有效性(需提前将生成的nonce存入Session或缓存)
    var storedNonce = HttpContext.Session.GetString("OpenIdNonce");
    if (storedNonce != nonce)
    {
        return BadRequest("无效的Nonce,可能存在重放攻击");
    }
    HttpContext.Session.Remove("OpenIdNonce");

    // 3. 使用关联时获取的mac_key验证响应签名
    var macKey = "YOUR_STORED_MAC_KEY"; // 替换为实际的mac_key
    if (!ValidateOpenIdSignature(requestParams, macKey))
    {
        return BadRequest("响应签名验证失败");
    }

    // 4. 提取Simple Registration扩展的用户信息
    var userClaims = new List<Claim>();
    if (requestParams.TryGetValue("openid.sreg.nickname", out var nickname))
        userClaims.Add(new Claim(ClaimTypes.Name, nickname));
    if (requestParams.TryGetValue("openid.sreg.email", out var email))
        userClaims.Add(new Claim(ClaimTypes.Email, email));
    if (requestParams.TryGetValue("openid.sreg.fullname", out var fullname))
        userClaims.Add(new Claim("fullname", fullname));

    // 5. 创建认证票据并完成登录
    var claimsIdentity = new ClaimsIdentity(userClaims, "OpenId2");
    var authProperties = new AuthenticationProperties();
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);

    return RedirectToAction("Index", "Home");
}

// 实现OpenID 2.0的HMAC-SHA1签名验证逻辑
private bool ValidateOpenIdSignature(Dictionary<string, string> parameters, string macKey)
{
    // 按照规范构建签名基字符串
    var signedParams = parameters["openid.signed"].Split(',');
    var baseString = string.Join("\n", signedParams.Select(p => $"{p}:{parameters[$"openid.{p}"]}"));

    // 计算HMAC-SHA1签名并对比
    var hmac = new HMACSHA1(Encoding.ASCII.GetBytes(macKey));
    var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(baseString));
    var computedSignature = Convert.ToBase64String(hash);

    return parameters["openid.sig"] == computedSignature;
}

关键注意事项

  • Realm与Return_to一致性:openid.realm必须是return_to的父域名/路径,Rediris会严格校验这一点,确保你的realm是http://localhost:5002/,return_to是该域名下的合法路径。
  • 关联信息存储:assoc_handle、mac_key、expires_in需要存入缓存或数据库,确保认证请求时使用未过期的有效关联。
  • Nonce管理:生成的nonce要存入Session或缓存,回调时验证后立即删除,避免被重复使用。

内容的提问来源于stack exchange,提问作者Francisco Reyes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:56:34