一个 ASP.NET Core 项目基于 Microsoft.AspNetCore.Authentication.OpenIdConnect 实现 OpenId 登录,
public class AuthenticationController : Controller
{
[Route("signin")]
public ActionResult LogIn(string returnUrl)
{
return Challenge(
new AuthenticationProperties { RedirectUri = returnUrl },
OpenIdConnectDefaults.AuthenticationScheme);
}
}
登录后发现 User.Identity.Name 的值为 null,请问如何解决?
[Authorize]
[Route("userinfo")]
public IActionResult UserInfo()
{
_logger.LogInformation("Current user login name is {loginName}", User.Identity.Name);
return Ok(new { User.Identity.Name });
}
User.Identity.Name
是根据 User.Identity.NameClaimType
从 User.Claims
中读取的,可以通过打印 User.Identity.NameClaimType 与 User.Claims 的值定位问题。
2种情况会造成 User.Identity.Name 为 null,一种是 User.Claims 中没有对应的 claim,一种是 NameClaimType 名称不匹配,今天我们遇到的这个问题是两种情况的叠加。
一是基于 OpenIddict 实现的 authorization server 漏写了下面这行代码
principal.SetScopes(request.GetScopes());
引起 new Claim(Claims.Name, user.LoginName)
这个 claim 在请求 /connect/token
时没有返回客户端应用,造成 User.Claims 中根本就没有对应的 claim。
二是 AddOpenIdConnect() 中 TokenValidationParameters 这行代码代码将 User.Identity.NameClaimType 设置成了 name
,而默认是 http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
(ClaimTypes.Name),造成 NameClaimType 名称不匹配,删除下面这行代码,问题就解决了。
services.AddCnblogsAuthentication(Configuration)
.AddOpenIdConnect(options =>
{
options.TokenValidationParameters.NameClaimType = "name";
});
注:authorization server 中 new Claim(Claims.Name, user.LoginName)
时虽然没有使用 ClaimTypes.Name,但客户端应用默认拿到手的也是 http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
这个名称。