繁体   English   中英

IdentityServer4:HttpContext GetToken null 但令牌是从服务器传递的

[英]IdentityServer4: HttpContext GetToken null but Token is delivered from server

我现在已经设法设置了一个 IdentityServer 应用程序和一个单独的 MVC 客户端应用程序,其中 IdentityServer 使用 MVC 应用程序的用户数据库。 MVC 应用程序用于用户注册、登录、注销和调用其他 API。

我可以登录到 MVC 应用程序并从 IdentityServer 获取正确的令牌。 但是现在我有两个问题:

  1. HttpContext 中的令牌为空,尽管 IdentityServer 成功发出令牌。 但是当我尝试从 HttpContext 访问令牌时,以下两个变体都不起作用:
var accessToken = await HttpContext.GetTokenAsync("access_token");
var accessToken = await HttpContext.GetTokenAsync(IdentityConstants.ExternalScheme, "access_token");

可能是因为我在 VS2017 中使用“dotnet run”而不是 IIS 启动了两个项目吗?

  1. 我在哪里或如何保存客户端的令牌以供将来调用 API? 理想情况下,每次请求都会自动发送令牌。 我忘记了这里的配置吗?

这是我的配置的样子:

身份服务器应用程序:

启动文件

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    var builder = services.AddIdentityServer(options =>
    {
        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;
    })
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApis())
        .AddInMemoryClients(Config.GetClients())
        .AddAspNetIdentity<ApplicationUser>();

    if (Environment.IsDevelopment())
    {
        builder.AddDeveloperSigningCredential();
    }
    else
    {
        throw new Exception("need to configure key material");
    }
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseStaticFiles();
    app.UseIdentityServer();
    app.UseMvcWithDefaultRoute();
}

配置文件

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
    };
}

public static IEnumerable<ApiResource> GetApis()
{
    return new List<ApiResource>
    {
        new ApiResource("api1", "My API")
    };
}

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },

            RedirectUris           = { "http://localhost:5002/signin-oidc" },
            PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

            AllowedScopes =
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                "api1"
            },

            AllowOfflineAccess = true
        }
    };
}

MVC 客户端应用程序:

启动文件

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    services.AddDefaultIdentity<IdentityUser>()
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

    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 = "mvc";
            options.ClientSecret = "secret";
            options.ResponseType = "code id_token";

            options.SaveTokens = true;
            options.GetClaimsFromUserInfoEndpoint = true;

            options.Scope.Add("api1");
            options.Scope.Add("offline_access");

            options.ClaimActions.MapJsonKey("website", "website");
        });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseAuthentication();

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseMvcWithDefaultRoute();
}

测试控制器

public async Task<IActionResult> LoginTest()
{
    var client = new HttpClient();
    var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
    if (disco.IsError)
    {
        Console.WriteLine(disco.Error);
    }

    var tokenClient = new TokenClient(disco.TokenEndpoint, "mvc", "secret");
    var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("myusername", "mypassword");

    if (tokenResponse.IsError)
    {
        Console.WriteLine(tokenResponse.Error);
    }

    Console.WriteLine(tokenResponse.Json);
    Console.WriteLine("\n\n");


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

    return View();
}

tokenResponse 已成功填充:

info: IdentityServer4.Events.DefaultEventService[0]
{
"Name": "Token Issued Success",
"Category": "Token",
"EventType": "Success",
"Id": 2000,
"ClientId": "mvc",
"ClientName": "MVC Client",
"Endpoint": "Token",
"SubjectId": "08be5c35-5593-49f4-999b-e5ddd694f2e9",
"Scopes": "openid profile api1 offline_access",
"GrantType": "password",
"Tokens": [
  {
    "TokenType": "refresh_token",
    "TokenValue": "****55a0"
  },
  {
    "TokenType": "access_token",
    "TokenValue": "****YuFw"
  }
],
"ActivityId": "0HLMAGC28PO61:00000001",
"TimeStamp": "2019-04-26T20:09:27Z",
"ProcessId": 21208,
"LocalIpAddress": "::1:5000",
"RemoteIpAddress": "::1"
}

我是 IdentityServer 的新手,到目前为止我已经开发了一个带有 WebAPI 的 SPA 并将 JWT 存储在 localstore 中。 我认为使用 MVC 客户端和 IdentityServer 有一种更舒适的方法来做到这一点。

当您注册 OIDC 中间件时

options.ResponseType = "code id_token";

您的客户端应用程序中不需要任何登录控制器。 中间件会将您的用户重定向到登录页面,即 IdentityServer 的授权端点 只需将Authorize属性添加到任何受保护的控制器中,您就应该拥有:

string accessToken = await HttpContext.GetTokenAsync("access_token");
string idToken = await HttpContext.GetTokenAsync("id_token");

您在示例LoginTest()方法中LoginTest()是直接调用令牌端点,它不使用 OIDC 中间件,因此不会登录您的用户(未创建用户会话),而只是验证您提供的凭据并创建令牌。 要使用所有协议功能,您还需要更改

AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

AllowedGrantTypes = GrantTypes.Hybrid, //or .Code

就是这样

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM