如何在 .Net core 2.0 中从 HttpContext 获取访问令牌

77

我正在尝试将一个项目从.Net Core 1.1升级到.Net Core 2.0,但有很多破坏性变更。

我目前遇到的问题之一是HttpContext.Authentication现在已过时。

我一直在尝试找出如何获取当前请求的访问令牌。我需要调用另一个需要承载令牌的API。

旧方法 .Net Core 1.1

[Authorize]
public async Task<IActionResult> ClientUpdate(ClientModel client)
{
    var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");
    return View();
}

方法 .Net core 2.0

这不起作用是因为上下文未注册。

[Authorize]
public async Task<IActionResult> ClientUpdate(ClientModel client)
{
    var accessToken = await context.HttpContext.GetTokenAsync("access_token"); 
    return View();
}

无法解析类型为 'Microsoft.AspNetCore.Http.HttpContext' 的服务

我尝试过注册,但那也不起作用

public ConsoleController(IOptions<ServiceSettings> serviceSettings, HttpContext context) 
在 startup.cs 文件中。
services.TryAddSingleton<HttpContext, HttpContext>();

更新:

这会返回 null

var accessToken = await HttpContext.GetTokenAsync("access_token");  

Startup.cs ConfigureServices

如果有什么问题,很可能是在启动项里面,因为这里有很多重大变化。

services.Configure<ServiceSettings>(Configuration.GetSection("ServiceSettings"));
//services.TryAddSingleton<HttpContext, HttpContext>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMvc();
services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect(options =>
        {
            options.Authority = "http://localhost:5000";
            options.ClientId = "testclient";
            options.ClientSecret = "secret";
            options.ResponseType = "code id_token";
            options.RequireHttpsMetadata = false;
            options.GetClaimsFromUserInfoEndpoint = true;
        });

Startup.cs 配置

loggerFactory.AddDebug();
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseBrowserLink();
}
else
{
    app.UseExceptionHandler("/Home/Error");
}
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

您无需注册HttpContext。它已经在您的控制器类中可用,就像在1.1中一样。 - Brad
@Brad,这正是我所想的,但我无法访问它,请描述一下你的意思。 - Linda Lawton - DaImTo
你的控制器是否继承自Controller类? - Brad
如果 GetAccessToken() 返回 null,则很可能是身份验证配置出了问题。您在启动时如何配置身份验证? - Brad
1
ClientUpdate在同一个ConsoleController中,所以我想是的? - Linda Lawton - DaImTo
显示剩余4条评论
10个回答

116

.Net core 2.1访问JWT承载令牌

var accessToken = Request.Headers[HeaderNames.Authorization];

3
据@El Mac所说,我在“Startup.ConfigureServices”方法中的“AddOpenIdConnect”方法中漏掉了“options.SaveTokens = true”。 - El Mac
3
这不仅返回令牌,还包括来自头部的授权方案("Bearer "),因此如果您只想要令牌,您需要提取它。 - Thomas Levesque
1
有没有不硬编码 "Authorization" 字符串的方法?那个字符串是否在某处定义为常量或枚举? - Tobias
6
“Request” 是从哪里发起的? - manymanymore
显示剩余6条评论

54

如果您想要纯净的令牌,在 .net core 3.1 中可以帮助您。

var _bearer_token = Request.Headers[HeaderNames.Authorization].ToString().Replace("Bearer ", "");

还要记得,您需要使用以下方式添加

using Microsoft.Net.Http.Headers;

3
非常简洁。建议在try...catch下进行包装,但是可选的。 - Prem
3
请使用“HttpContext.GetTokenAsync("access_token")”代替。 - stfno.me

34

最终发现是配置问题。为了读取cookie到标头中,AddAuthentication和AddOpenIdConnect之间需要建立链接。

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";

                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;

                options.ClientId = "testclient";
                options.ClientSecret = "secret";
                options.ResponseType = "code id_token";
                options.SaveTokens = true;
                options.GetClaimsFromUserInfoEndpoint = true;

                options.Scope.Add("testapi");
                options.Scope.Add("offline_access");
            });

控制器

    [Authorize]
    public async Task<IActionResult> Index()
    {
        var accessToken = await HttpContext.GetTokenAsync("access_token");
        return View();
    }

访问令牌现在已经填充。

注意:最终我从这个项目的Startup.cs文件中挖掘出它。


1
你的控制器中不需要使用 IHttpContextAccessor。因为 HttpContext 属性已经包含在其中了。 - Brad
2
你的配置错误了,正如这个答案明确指出的那样。如果HttpContext没有被填充,你本来会得到NullReferenceException异常。这就是我所说的身份验证配置! - Brad
1
你从哪里得到了 access_token 这个名称?这是一些著名的属性吗?你能分享一下文档的参考资料吗? - Stanislav Berkov
是的,访问令牌是标准的。它是来自授权响应的一部分。 - Linda Lawton - DaImTo

29
在控制器中,可以通过读取Request.Headers字典来检索令牌。
 var accessToken = Request.Headers["Authorization"];
在HttpContext不可用的其他类中,可以使用HttpContextAccessor从服务集合中注入来检索token(与Azharuddin答案有所不同)。 在Startup方法中注册服务实例。
public void ConfigureServices(IServiceCollection services)
{

 services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 ...
}

然后在您的控制器中注入依赖项,如下所示:

private IHttpContextAccessor _httpContextAccessor;
public ClientController(IHttpContextAccessor httpContextAccessor)
{
     _httpContextAccessor = httpContextAccessor;
}

像这样在您的操作中获取访问令牌:

[Authorize]
public async Task<IActionResult> ClientUpdate(ClientModel client)
{
    var accessToken = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];

    ..........//Some other code
    return View();
}

5

Startup.cs:

 public void ConfigureServices(IServiceCollection services)
 {
    ...
     services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    ...
 }

控制器构造函数:

private IHttpContextAccessor _httpContextAccessor;
public ClientController(IHttpContextAccessor httpContextAccessor)
{
     _httpContextAccessor = httpContextAccessor;
}

[Authorize]
public async Task<IActionResult> ClientUpdate(ClientModel client)
{
    var accessToken = await _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
    return View();
}

这应该可以工作。


这行编程代码对我来说有效:var token = HttpContext.Request.Headers["Authorization"][0]; @user1672994 小写字母拼错了,应该是 Authorization。 - Enrico

2
string accessToken = Request.Headers[HeaderNames.Authorization].ToString().Replace($"{JwtBearerDefaults.AuthenticationScheme} ", String.Empty);

2

您需要指定外部模式来检索令牌。

var accessToken = await HttpContext.GetTokenAsync(IdentityConstants.ExternalScheme, "access_token");

0

非常感谢,这太完美了!

我已经完成了这项工作,但是使用了我们的 Azure 租户专用权限。只需将******替换为您的租户名称即可。

options.Authority = "https://login.microsoftonline.com/******.onmicrosoft.com";

您还可以使用租户 ID。只需在https://login.microsoftonline.com/后面插入您的租户 ID。

options.Authority = "https://login.microsoftonline.com/be0be093-****-****-****-5626e83beefc";

0
我的项目针对 .Net 7。
string? jwtToken = HttpContext.Request.Headers.Authorization.FirstOrDefault()?.Split(" ").Last();

-5

应该是HttpContext.GetTokenAsync("access_token").Result.ToString();


4
在异步操作中阻塞异步方法是一个非常糟糕的想法,也无法解决任何命名空间问题。 - Panagiotis Kanavos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接