c# - 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这是我在堆栈上的第一篇文章:)
解决方案
推荐阅读
- php - 即使我在代码中编写了其他内容,也无法打开“NANphp”
- sql - 使用 Join 根据过滤器 WHERE 包含所有行
- terraform - 将计数更改为 for_each Terraform
- angular - Angular OAuth2 检查 Guard 中的权限
- c# - 在返回导航中跳过 xamarin 表单中的页面
- python - 尝试通过网状包在 R 中使用 Python Gekko 时出错
- tfs - TFS2015 看不到项目文件,不能签入任何东西
- oracle - 我可以在 Oracle 数据库的 EXCEPTION 处理程序中获取 SQLSTATE 值吗?
- c++ - rapidjson 擦除数组并释放内存
- php - PhpStorm 调试问题