在同一IS4 Web应用程序上获取access_token工作调用API

问题描述

我正在尝试使这个access_token东西起作用,以调用从BaseController用Autohorize属性声明的API。我认为我的配置有问题。 有人可以告诉我我在做什么错吗?

我已附上Startup.cs供参考。 我正在尝试使用以下代码中调用的API来获取访问令牌:

   var httpClient = _httpClientFactory.CreateClient(BaseController.AUTHORIZATION_SERVICE_CLIENT_NAME);
   httpClient.DefaultRequestHeaders.Clear();
   httpClient.DefaultRequestHeaders.Add(HeaderNames.Accept,"application/json");

//AccessToken is always null
   var accessToken = _httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result;
   httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",accessToken);

   var request = new HttpRequestMessage(HttpMethod.Get,"/api/auth/user/?id=" + id);
   var response = httpClient.SendAsync(request,HttpCompletionOption.ResponseHeadersRead).Result;
   if (response.IsSuccessStatusCode)
      return response.Content.ReadAsStringAsync().Result as string;
   return "-";

我的IS4启动: 确认

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddMvc().AddDataAnnotationsLocalization();

    services.AddRazorPages()
        .AddRazorPagesOptions(options =>
        {
            options.Conventions.AuthorizeAreaFolder("Identity","/Account/Manage");
        });

//START IS4
var builder = services.AddIdentityServer(options =>
{
    options.Events.RaiseErrorEvents = true;
    options.Events.RaiseInformationEvents = true;
    options.Events.RaiseFailureEvents = true;
    options.Events.RaiseSuccessEvents = true;
    options.UserInteraction.LoginUrl = "/Identity/Account/Login";
    options.UserInteraction.LogoutUrl = "/Identity/Account/Logout";
    options.Authentication = new AuthenticationOptions()
    {
        CookieLifetime = TimeSpan.FromHours(10),// ID server cookie timeout set to 10 hours
        CookieSlidingExpiration = true
    };
})
.AddConfigurationStore(options =>
{
    options.ConfigureDbContext = b => b.UseSqlServer(connectionString,sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
    options.ConfigureDbContext = b => b.UseSqlServer(connectionString,sql => sql.MigrationsAssembly(migrationsAssembly));
    options.EnableTokenCleanup = true;
})
.AddAspNetIdentity<User>();

if (env.IsDevelopment())
    builder.AddDeveloperSigningCredential();
else
    builder.AddSigningCredential(LoadCertificateFromStore());

//END IS4

//START IDENTITY
services.AddIdentity<User,Role>(options =>
{
    options.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<IdentityContext>()
.AddUserStore<CustomUserStore>()
.AddRoleStore<CustomRoleStore>()
.AddDefaultTokenProviders()
.AddClaimsPrincipalFactory<CustomUserClaimsPrincipalFactory>();

services.ConfigureApplicationCookie(options => {
    options.LoginPath = Startup.LoginPath;
    options.LogoutPath = Startup.LogoutPath;
    options.AccessDeniedPath = Startup.AccessDeniedPath;
});

services.AddAuthentication(o =>{})
      .AddGoogle("Google","Google",options =>
        {
            options.SignInScheme = IdentityConstants.ExternalScheme;
            options.ClientId = configuration.GetValue<string>("Google:ClientId");
            options.ClientSecret = configuration.GetValue<string>("Google:ClientSecret");
        })
        .AddOpenIdConnect("azuread","Azure AD",options => configuration.Bind("AzureAd",options));

services.Configure<OpenIdConnectOptions>("azuread",options =>
{
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Events = new OpenIdConnectEvents()
    {
        OnRedirectToIdentityProviderForSignOut = context =>
        {
            context.HandleResponse();
            context.Response.Redirect("/Identity/Account/Logout");
            return Task.FromResult(0);
        }
    };
});

services.AddTransient<IClaimsTransformation,ClaimsTransformer>();

//END IDENTITY

    //Set named HttpClient settings for API to get roles of user
    services.AddHttpContextAccessor();            
    services.AddTransient<BearerTokenHandler>();
    services.AddHttpClient(BaseController.AUTHORIZATION_SERVICE_CLIENT_NAME,client =>
    {
        client.BaseAddress = new Uri("https://localhost:44318/");
    }).AddHttpMessageHandler<BearerTokenHandler>();
}

public void Configure(IApplicationBuilder app)
{
    if (Environment.IsDevelopment())
    {
        Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler(ErrorPath);
    }

    app.UseStaticFiles();
    app.UseRouting();

    app.UseIdentityServer();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(name: "defaultArea",pattern: "{area=Identity}/{controller=Account}/{action=Login}/{id?}");
        endpoints.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapRazorPages();
    });
}

Bearer令牌处理程序,当我向客户端添加'AddHttpMessageHandler


protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
{
    var accessToken = await GetAccessTokenAsync();
    if (!string.IsNullOrWhiteSpace(accessToken))
        request.SetBearerToken(accessToken);

    return await base.SendAsync(request,cancellationToken);
}

public async Task<string> GetAccessTokenAsync()
{
    // get the expires_at value & parse it
    var expiresAt = await _httpContextAccessor.HttpContext.GetTokenAsync("expires_at");
    var expiresAtAsDateTimeOffset = DateTimeOffset.Parse(expiresAt,CultureInfo.InvariantCulture);

    if ((expiresAtAsDateTimeOffset.AddSeconds(-60)).ToUniversalTime() > DateTime.UtcNow)
        return await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken); // no need to refresh,return the access token

    var idpClient = _httpClientFactory.CreateClient("IDPClient");

    // get the discovery document
    var discoveryReponse = await idpClient.GetDiscoveryDocumentAsync();

    // refresh the tokens
    var refreshToken = await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);

    var refreshResponse = await idpClient.RequestRefreshTokenAsync(new RefreshTokenRequest {
            Address = discoveryReponse.TokenEndpoint,ClientId = "mvc",ClientSecret = "secret",RefreshToken = refreshToken
        });

    // store the tokens             
    var updatedTokens = new List<AuthenticationToken>();
    updatedTokens.Add(new AuthenticationToken {
        Name = OpenIdConnectParameterNames.IdToken,Value = refreshResponse.IdentityToken
    });
    updatedTokens.Add(new AuthenticationToken {
        Name = OpenIdConnectParameterNames.AccessToken,Value = refreshResponse.AccessToken
    });
    updatedTokens.Add(new AuthenticationToken {
        Name = OpenIdConnectParameterNames.RefreshToken,Value = refreshResponse.RefreshToken
    });
    updatedTokens.Add(new AuthenticationToken {
        Name = "expires_at",Value = (DateTime.UtcNow + TimeSpan.FromSeconds(refreshResponse.ExpiresIn)).
                ToString("o",CultureInfo.InvariantCulture)
    });

    // get authenticate result,containing the current principal & properties
    var currentAuthenticateResult = await _httpContextAccessor.HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    // store the updated tokens
    currentAuthenticateResult.Properties.StoreTokens(updatedTokens);

    // sign in
    await _httpContextAccessor.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,currentAuthenticateResult.Principal,currentAuthenticateResult.Properties);

    return refreshResponse.AccessToken;
}

解决方法

一个想法可能是尝试在您的配置中设置SaveTokens = true。

请参阅此article或想法。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...