首页 > 解决方案 > IdentityServer4 Session Cookie Management(如何正确操作?)

问题描述

我们正在开发一个 idetityserver4(角度的 SPA 应用程序),它将在独立服务器上运行,并将与另一台服务器上的 API(asp.net API)通信,我们试图实现的模式是 BFF(后端前端),如果我们没有误解这个概念,我们的 ID4 将充当 API 的网关,首先我们使用 ClientID 和秘密登录到 ID4,以便我们获取令牌并生成会话 cookie,然后我们将所有内容转发到 API 以完成本地登录。到目前为止一切正常,我们得到了我们想要的响应,令牌被设置为访问 API,并且为该客户端生成的 cookie 会自动在 Header 中返回(我们使用 POSTMAN),

以下是片段

启动.cs

services.AddAuthentication(options =>
        {
            options.DefaultScheme = "cookies";
            options.DefaultChallengeScheme = "oidc";
            options.RequireAuthenticatedSignIn = true;
        })
    .AddCookie("cookies", options =>
    {
        options.Cookie.Name = "cookie-bff";
        options.Cookie.SameSite = SameSiteMode.Strict;
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(1);
        options.Cookie.SecurePolicy = 0;
        options.SlidingExpiration = true;
        options.Events.OnSigningOut = async e =>
        {
            // revoke refresh token on sign-out
            await e.HttpContext.RevokeUserRefreshTokenAsync();
        };
    })
    .AddOpenIdConnect("oidc", options =>
    {
        options.Authority = "https://localhost:4001/";
        options.ClientId = "angular-client";
        options.ClientSecret = "secret";

        options.ResponseType = "code";
        options.GetClaimsFromUserInfoEndpoint = true;
        options.SaveTokens = true;
        /*
        options.Scope.Clear();
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("api");
        options.Scope.Add("offline_access");
        */
        options.TokenValidationParameters = new TokenValidationParameters
        {
            NameClaimType = "name",
            RoleClaimType = "role"
        };
    });

        services.AddAccessTokenManagement(options =>
        {
            // client config is inferred from OpenID Connect settings
            // if you want to specify scopes explicitly, do it here, otherwise the scope parameter will not be sent
            options.Client.Scope = "write";
        })
        .ConfigureBackchannelHttpClient();

        services.AddUserAccessTokenClient("user_client", client =>
        {
            client.BaseAddress = new Uri("https://localhost:5001/api/");
        });

        services.AddClientAccessTokenClient("client", configureClient: client =>
        {
            client.BaseAddress = new Uri("https://localhost:5001/api/");
        });

我们在哪里配置 Context 进行操作和配置

 services.AddIdentityServer(options => {
            options.Authentication.CheckSessionCookieName = "cookie-bff";
            options.Authentication.CookieLifetime = TimeSpan.FromMinutes(1);
            options.Authentication.CookieSameSiteMode = SameSiteMode.Strict;
            options.Authentication.CookieSlidingExpiration = true;
            options.LowerCaseIssuerUri = false;
            options.EmitScopesAsSpaceDelimitedStringInJwt = false;
            })
                .AddDeveloperSigningCredential()
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = b => b.UseSqlServer(configuration.GetConnectionString("LocalDevelopment"),
                        sql => sql.MigrationsAssembly(migrationAssembly));
                })
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = b => b.UseSqlServer(configuration.GetConnectionString("LocalDevelopment"),
                        sql => sql.MigrationsAssembly(migrationAssembly));
                });

这是我们的 LoginController(它的工作正在进行中,我们是初学者)

[HttpPost]
    [Route("/identityserver/login")]
    public async Task<IActionResult> Post([Required, FromBody] LoginPostDTO Json)
    {
        var client = new HttpClient();

        var response = await client.RequestTokenAsync(new TokenRequest
        {
            Address = "https://localhost:4001/connect/token",
            GrantType = "client_credentials",

            ClientId = "angular-client",
            ClientSecret = "secret",

            Parameters =
{
    { "scope", "read"},
    {"openid","profile"}
}
        });
       
        var claims = new List<Claim>
            {
                new Claim(JwtClaimTypes.Name,"Company"),
                new Claim(JwtClaimTypes.Role, "Administrator"),
                new Claim(JwtClaimTypes.Subject, "Company")
            };

        var claimsIdentity = new ClaimsIdentity(claims, "cookies");

        var authProperties = new AuthenticationProperties
        {
            AllowRefresh = true,
            // Refreshing the authentication session should be allowed.

            ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(1),
            // The time at which the authentication ticket expires. A 
            // value set here overrides the ExpireTimeSpan option of 
            // CookieAuthenticationOptions set with AddCookie.

            IsPersistent = false,
            // Whether the authentication session is persisted across 
            // multiple requests. When used with cookies, controls
            // whether the cookie's lifetime is absolute (matching the
            // lifetime of the authentication ticket) or session-based.

            IssuedUtc = DateTime.Now,
            // The time at which the authentication ticket was issued.

            RedirectUri = "https://localhost:4001/signin-oidc"
            // The full path or absolute URI to be used as an http 
            // redirect response value.
        };

        await HttpContext.SignInAsync("cookies", new ClaimsPrincipal(claimsIdentity), authProperties);

        var stringContent = new StringContent(JsonConvert.SerializeObject(Json), Encoding.UTF8, "application/json");

        var api = new HttpClient();
        api.SetBearerToken(response.AccessToken);

        var apiResponse = await api.PostAsync("https://localhost:5001/api/login", stringContent);

        return Ok(apiResponse.Content.ReadAsAsync(typeof(JObject)).Result);
    }
}

这是我们登录后与 API 通信的控制器

public class Controller : ControllerBase
{
    [HttpPost]
    [Route("/identityserver/request")]
    [Produces("application/json")]
    [Consumes("application/json")]
    public async Task<IActionResult> Post([Required, FromBody]DTO Json)
    {   
        var stringContent = new StringContent(JsonConvert.SerializeObject(Json), Encoding.UTF8, "application/json");

        var api = new HttpClient();
        api.SetBearerToken(await HttpContext.GetClientAccessTokenAsync());

        var apiResponse = await api.PostAsync("https://localhost:5001/api/request/medical-request", stringContent);

        return Ok(apiResponse.Content.ReadAsAsync(typeof(JObject)).Result);
    }
}

先感谢您!

PS这是我在堆栈上的第一篇文章:)

标签: c#asp.net-web-apiidentityserver4single-page-applicationsession-cookies

解决方案


推荐阅读