簡體   English   中英

OpenIddict,重新啟動身份驗證服務器后,令牌將失效

[英]OpenIddict, after restarting auth server the tokens are invalidated

我進行了以下設置:授權服務器(帶 MVC 的 .NET 6,端口 7000),客戶端(帶 MVC 的 .NET 6,端口 7001),資源服務器(.NET 6 API,端口 7002)。

授權服務器設置:

builder.Services.AddAuthentication()
   .AddGoogle(options =>
   {
       options.ClientId = builder.Configuration["ClientId"];
       options.ClientSecret = builder.Configuration["ClientSecret"];
   });

builder.Services.Configure<IdentityOptions>(options =>
{
    options.ClaimsIdentity.UserNameClaimType = Claims.Name;
    options.ClaimsIdentity.UserIdClaimType = Claims.Subject;
    options.ClaimsIdentity.RoleClaimType = Claims.Role;
    options.ClaimsIdentity.EmailClaimType = Claims.Email;

    options.SignIn.RequireConfirmedAccount = false;
});

builder.Services.AddOpenIddict()
    .AddCore(options =>
    {
        options.UseEntityFrameworkCore()
                .UseDbContext<AuthorizationContext>();
    })
    .AddServer(options =>
    {
        options.SetAuthorizationEndpointUris("/connect/authorize")
                .SetLogoutEndpointUris("/connect/logout")
                .SetTokenEndpointUris("/connect/token")
                .SetUserinfoEndpointUris("/connect/userinfo")
                .SetIntrospectionEndpointUris("/connect/introspect");

        options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles);

        options.AllowAuthorizationCodeFlow();

        options.AddDevelopmentEncryptionCertificate()
                .AddDevelopmentSigningCertificate();

        options.UseAspNetCore()
                .EnableAuthorizationEndpointPassthrough()
                .EnableLogoutEndpointPassthrough()
                .EnableTokenEndpointPassthrough()
                .EnableUserinfoEndpointPassthrough()
                .EnableStatusCodePagesIntegration();
    })
    .AddValidation(options =>
    {
        options.UseLocalServer();

        options.UseAspNetCore();
    });

builder.Services.AddHostedService<Worker>();

種子客戶:

            await manager.CreateAsync(new OpenIddictApplicationDescriptor
            {
                ClientId = "mvc",
                ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
                ConsentType = ConsentTypes.Explicit,
                DisplayName = "MVC client application",
                PostLogoutRedirectUris =
                {
                    new Uri("https://localhost:7001/signout-callback-oidc")
                },
                    RedirectUris =
                {
                    new Uri("https://localhost:7001/signin-oidc")
                },
                    Permissions =
                {
                    Permissions.Endpoints.Authorization,
                    Permissions.Endpoints.Logout,
                    Permissions.Endpoints.Token,
                    Permissions.GrantTypes.AuthorizationCode,
                    Permissions.GrantTypes.RefreshToken,
                    Permissions.ResponseTypes.Code,
                    Permissions.Scopes.Email,
                    Permissions.Scopes.Profile,
                    Permissions.Scopes.Roles,
                    Permissions.Prefixes.Scope + "api1"
                },
                    Requirements =
                {
                    Requirements.Features.ProofKeyForCodeExchange
                }
            });

            // resource server
            if (await manager.FindByClientIdAsync("resource_server_1") == null)
            {
                var descriptor = new OpenIddictApplicationDescriptor
                {
                    ClientId = "resource_server_1",
                    ClientSecret = "846B62D0-DEF9-4215-A99D-86E6B8DAB342",
                    Permissions =
                        {
                            Permissions.Endpoints.Introspection
                        }
                };

                await manager.CreateAsync(descriptor);
            }

客戶端配置:

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.LoginPath = "/login";
    options.ExpireTimeSpan = TimeSpan.FromMinutes(50);
    options.SlidingExpiration = false;
})
.AddOpenIdConnect(options =>
{
    options.ClientId = "mvc";
    options.ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654";

    options.RequireHttpsMetadata = false;
    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true;

    options.ResponseType = OpenIdConnectResponseType.Code;
    options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;

    options.Authority = "https://localhost:7000/";

    options.Scope.Add("email");
    options.Scope.Add("roles");
    options.Scope.Add("api1");

    options.MapInboundClaims = false;

    options.TokenValidationParameters.NameClaimType = "name";
    options.TokenValidationParameters.RoleClaimType = "role";
});

資源服務器配置:

builder.Services.AddOpenIddict()
    .AddValidation(options =>
    {
        options.SetIssuer("https://localhost:7000/");
        options.AddAudiences("resource_server_1");

        options.UseIntrospection()
               .SetClientId("resource_server_1")
               .SetClientSecret("846B62D0-DEF9-4215-A99D-86E6B8DAB342");

        options.UseSystemNetHttp();

        options.UseAspNetCore();
    });

builder.Services.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);

這是客戶端向資源服務器發出請求的方式:

    [Authorize, HttpPost("~/")]
    public async Task<ActionResult> Index(CancellationToken cancellationToken)
    {
        var token = await HttpContext.GetTokenAsync(CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectParameterNames.AccessToken);
        if (string.IsNullOrEmpty(token))
        {
            throw new InvalidOperationException("The access token cannot be found in the authentication ticket. " +
                                                "Make sure that SaveTokens is set to true in the OIDC options.");
        }

        using var client = _httpClientFactory.CreateClient();

        using var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:7002/api/message");
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);

        using var response = await client.SendAsync(request, cancellationToken);
        var content = await response.Content.ReadAsStringAsync();
        response.EnsureSuccessStatusCode();

        return View("Home", model: await response.Content.ReadAsStringAsync());
    }

當我設置這 3 個實例(auth 服務器、客戶端、資源服務器)並且我未在客戶端(無 cookie)中進行身份驗證時,問題就出現了。 我可以在客戶端進行身份驗證(因此在身份驗證服務器上)。 然后我從客戶端向資源服務器發出請求,它返回200

但后來我停止了所有 3 個實例並嘗試再次執行。

那時我已經在客戶端(cookies)中進行了身份驗證並且可以提取令牌(僅供參考,停止實例之前和之后的請求之間的令牌是相同的)。 但此令牌無效,資源服務器的響應代碼為401

在資源服務器日志上,我可以看到以下日志:“ OpenIddict.Validation.AspNetCore was not authenticated. Failure message: An error occurred while authenticating the current request ”,以及“ invalid_token, the specified token is invalid

問題:這是預期的行為嗎? 我認為原因是數據保護更改了密鑰環或類似的東西。 如果是預期的 - 那么如何在不重新驗證所有用戶的情況下進行重新部署?

我很確定問題出在這條線

    options.AddDevelopmentEncryptionCertificate()
            .AddDevelopmentSigningCertificate();

當您重新啟動應用程序時,這些證書(密鑰)會更改。 您需要准備好生產加密/簽名密鑰。

請參閱 options.AddEncryptionKey 和 options.AddSigningKey

密鑰可以這樣創建

var rsa = RSA.Create(2048);
var key = new RsaSecurityKey(rsa);

您可以獲得密鑰的 XML 並將其保存在某個地方 PRIVATE

var xml = key.Rsa.ToXmlString(true);

啟動應用程序時,使用 XML 加載密鑰

var rsa = RSA.Create();
rsa.FromXmlString(xml);

然后將密鑰添加到 openiddict

options.AddEncryptionKey(rsa);
options.AddSigningKey(rsa);

您可能還想改用以下方法

  • 選項.AddEncryptionCredentials
  • 選項.AddSigningCredentials
  • options.AddEncryptionCertificate
  • 選項.AddSigningCertificate

這取決於你有什么可用的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM