.Net Core OAuth 嵌套声明未映射回用户
.Net Core OAuth Nested Claims are not mapped back to user
我正在尝试在 OAuth 之后访问声明:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = COINBASE_AUTH_ID;
})
.AddCookie()
.AddOAuth(COINBASE_AUTH_ID, options =>
{
options.ClientId = Configuration["Coinbase:ClientId"];
options.ClientSecret = Configuration["Coinbase:ClientSecret"];
options.CallbackPath = new PathString("/signin-coinbase");
options.AuthorizationEndpoint = "https://www.coinbase.com/oauth/authorize";
options.TokenEndpoint = "https://api.coinbase.com/oauth/token";
options.UserInformationEndpoint = "https://api.coinbase.com/v2/user";
options.SaveTokens = true;
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
options.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
options.ClaimActions.MapJsonKey("urn:coinbase:avatar", "avatar_url");
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
request.Headers.Add("CB-VERSION", DateTime.Now.ToShortDateString());
var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
context.RunClaimActions(user);
}
};
});
据我了解,在 OnCreatingTicket 中获得访问令牌后,我通过 UserEndpoint 获得了一个用户。当我调用 context.RunClaimActions(user)
时,这应该将我在选项中设置的声明映射到我的用户。
在我的索引模型中,我尝试像这样获取映射的声明:
public class IndexModel : PageModel
{
public string CoinbaseId { get; set; }
public string CoinbaseAvatar { get; set; }
public string CoinbaseName { get; set; }
public async Task OnGetAsync()
{
if (User.Identity.IsAuthenticated)
{
CoinbaseName = User.FindFirst(c => c.Type == ClaimTypes.Name)?.Value;
CoinbaseId = User.FindFirst(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
CoinbaseAvatar = User.FindFirst(c => c.Type == "urn:coinbase:avatar")?.Value;
}
}
然而模型 return 全部为空值。我对 coinbase 的回复包含所有这 3 个声明,但它们似乎没有映射到我的内存用户,有人知道为什么吗?
编辑
事实证明,Coinbase 并不直接 return 用户对象,它 return 将用户对象包裹在一个名为 Data 的对象中。
我试过在我的地图前加上
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "data.id");
我想我需要手动解析数据对象
为了解决这个问题,我用 SelectToken
在 JObject 中抓取了嵌套的 属性
var userData = JObject.Parse(await response.Content.ReadAsStringAsync());
var user = userData["data"];
context.RunClaimActions(JObject.FromObject(user));
您可以使用 ClaimActions.MapJsonSubKey
导航到嵌套键。
我正在尝试在 OAuth 之后访问声明:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = COINBASE_AUTH_ID;
})
.AddCookie()
.AddOAuth(COINBASE_AUTH_ID, options =>
{
options.ClientId = Configuration["Coinbase:ClientId"];
options.ClientSecret = Configuration["Coinbase:ClientSecret"];
options.CallbackPath = new PathString("/signin-coinbase");
options.AuthorizationEndpoint = "https://www.coinbase.com/oauth/authorize";
options.TokenEndpoint = "https://api.coinbase.com/oauth/token";
options.UserInformationEndpoint = "https://api.coinbase.com/v2/user";
options.SaveTokens = true;
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
options.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
options.ClaimActions.MapJsonKey("urn:coinbase:avatar", "avatar_url");
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
request.Headers.Add("CB-VERSION", DateTime.Now.ToShortDateString());
var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
context.RunClaimActions(user);
}
};
});
据我了解,在 OnCreatingTicket 中获得访问令牌后,我通过 UserEndpoint 获得了一个用户。当我调用 context.RunClaimActions(user)
时,这应该将我在选项中设置的声明映射到我的用户。
在我的索引模型中,我尝试像这样获取映射的声明:
public class IndexModel : PageModel
{
public string CoinbaseId { get; set; }
public string CoinbaseAvatar { get; set; }
public string CoinbaseName { get; set; }
public async Task OnGetAsync()
{
if (User.Identity.IsAuthenticated)
{
CoinbaseName = User.FindFirst(c => c.Type == ClaimTypes.Name)?.Value;
CoinbaseId = User.FindFirst(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
CoinbaseAvatar = User.FindFirst(c => c.Type == "urn:coinbase:avatar")?.Value;
}
}
然而模型 return 全部为空值。我对 coinbase 的回复包含所有这 3 个声明,但它们似乎没有映射到我的内存用户,有人知道为什么吗?
编辑
事实证明,Coinbase 并不直接 return 用户对象,它 return 将用户对象包裹在一个名为 Data 的对象中。
我试过在我的地图前加上
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "data.id");
我想我需要手动解析数据对象
为了解决这个问题,我用 SelectToken
var userData = JObject.Parse(await response.Content.ReadAsStringAsync());
var user = userData["data"];
context.RunClaimActions(JObject.FromObject(user));
您可以使用 ClaimActions.MapJsonSubKey
导航到嵌套键。