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

Posted

技术标签:

【中文标题】如何从 .Net core 2.0 中的 HttpContext 获取访问令牌【英文标题】:How to get access token from HttpContext in .Net core 2.0 【发布时间】:2018-09-20 23:12:35 【问题描述】:

我正在尝试将一个项目从 .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 配置服务

如果这是初创公司的事情,我不会感到惊讶,因为这里也有很多重大变化。

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 这就是我的想法,但我无法访问它,请描述你的意思。 你的控制器是否继承自 Controller 类? 如果 GetAccessToken() 返回 null 可能是您的身份验证配置存在问题。您是如何在 Startup 中配置身份验证的? ClientUpdate 在同一个 ConsoleController 中,所以我不得不说是? 【参考方案1】:

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 做了一个小错字授权应该是授权【参考方案2】:

在Controller中,可以通过读取Request.Headers字典来获取token:

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

在 HttpContext 不可用的其他类中,可以在注入服务集合后使用HttpContextAccessor 检索令牌( 与 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();

【讨论】:

【参考方案3】:

如果您想要纯令牌,这可以在 .net core 3.1 中为您提供帮助

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

记住你需要添加这个使用

using Microsoft.Net.Http.Headers;

【讨论】:

非常清脆。建议使用 try...catch 包装,但可选。 这很好用!【参考方案4】:

.Net Core 2.1 访问 JWT 不记名令牌

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

【讨论】:

@El Mac 显然,我在 Startup.ConfigureServices 内的 AddOpenIdConnect 方法中缺少 options.SaveTokens = true。 ***.com/a/50623141/2632991 这不仅仅返回令牌。它还包括来自标头(“Bearer”)的身份验证方案,因此如果您只想要令牌,则必须提取它 有没有办法不对"Authorization" 字符串进行硬编码?该字符串是在某处定义为常量还是枚举? @Tobias Are there any constants for the default HTTP headers? Request 来自哪里?【参考方案5】:

您需要指定外部架构来检索令牌。

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

【讨论】:

【参考方案6】:

非常感谢,这太完美了!

我有这项工作,但有我们天蓝色的租户专用权限。只需将 ****** 替换为您的租户名称即可。

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

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

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

【讨论】:

【参考方案7】:

它最终成为配置问题。 AddAuthentication 和 AddOpenIdConnect 之间需要有一个链接,以便它将 cookie 读入标头中。

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

【讨论】:

您的控制器中不需要IHttpContextAccessor。它已经作为 HttpContext 属性存在。 原来如此!您的配置不正确,因为这个答案清楚地表明了这一点。如果没有填充HttpContext,您将获得NullReferenceException。这就是我所说的身份验证配置!

以上是关于如何从 .Net core 2.0 中的 HttpContext 获取访问令牌的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET CORE 2.0 中的 FromUri

Azure Functions .NET Core 中的 EF Core 2.0 连接字符串

如何将 UserManager 注入 ASP.NET Core 2.0 中的另一个服务

从.Net Core 2.0 Web应用程序中的apppsettings.json文件中读取值[重复]

ASP.Net Core 2.0 - 如何从中间件返回自定义 json 或 xml 响应?

无论用户登录如何,如何保护 Angular / .NET Core 2.0 应用程序中的所有 api 调用