c# - 获得新的 access_token 后如何更新我的 cookie?
问题描述
使用刷新令牌获取新的访问令牌后,我想使用该访问令牌更新我的客户端 cookie。
我的客户端能够使用 ajax 登录并调用我的 REST API,但是当第一次授权到期时,API 调用自然不再起作用。
我有一个使用自己的 REST API 的 .NET Web 应用程序。API 是同一个项目的一部分。它没有自己的启动配置。
由于 cookie 在每个请求的标头中发送,因此它需要具有新的未过期访问令牌,这样我就不会为请求获得“用户未授权”。
现在我可以使用我的刷新令牌获得一个新令牌,但 cookie 的值没有改变,所以我相信我需要在客户端发送任何请求之前更新我的 cookie 以反映新的访问令牌。
这是我的混合客户端:
using IdentityModel.Client;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace Cts.HomeService.Web.App_Start
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var identityServerSection = (IdentityServerSectionHandler)System.Configuration.ConfigurationManager.GetSection("identityserversection");
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager()
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = "localTestClient",
Authority = "http://localhost:5000",
RedirectUri = identityServerSection.Identity.RedirectUri,
Scope = "openid profile offline_access",
ResponseType = "code id_token",
RequireHttpsMetadata = false,
PostLogoutRedirectUri = identityServerSection.Identity.RedirectUri,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role",
},
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
var tokenClient = new TokenClient(
"http://localhost:5000/connect/token",
"localTestClient",
"");
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(
n.Code, n.RedirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
// use the access token to retrieve claims from userinfo
var userInfoClient = new UserInfoClient(
"http://localhost:5000/connect/userinfo");
var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);
// create new identity
var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
id.AddClaims(userInfoResponse.Claims);
id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
id.AddClaim(new Claim("id_token", tokenResponse.IdentityToken));
id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));
n.AuthenticationTicket = new AuthenticationTicket(
new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
{
// so here I'll grab the access token
if (isAccessTokenExpired()) {
var cancellationToken = new CancellationToken();
var newAccessToken = context.GetNewAccessTokenAsync(refresh_token, null, cancellationToken);
// now what?
}
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
}
}
});
}
}
}
我研究了很多东西,但我的 cookie 的价值始终保持不变。我考虑过删除旧 cookie 并手动构建新 cookie,但这需要以正确的方式对其进行加密,而且它闻起来很有趣,当然不是惯用的做法。
我觉得一定有一些我想念的简单的东西。我希望有一个简单的“UpdateCookie(newToken)”类型的方法,我已经尝试过 SignIn() 和 SignOut() 但这些对我来说都没有成功,实际上似乎根本没有与 cookie 交互。
解决方案
这就是我的工作方式,添加以下几行:
SecurityTokenValidated = context =>
{
context.AuthenticationTicket.Properties.AllowRefresh = true;
context.AuthenticationTicket.Properties.IsPersistent = true;
}
然后在 AuthorizationCodeReceived 中将其添加到末尾:
HttpContext.Current.GetOwinContext().Authentication.SignIn(new AuthenticationProperties
{
ExpiresUtc = DateTimeOffset.UtcNow.AddSeconds(tokenResponse.ExpiresIn),
AllowRefresh = true,
IssuedUtc = DateTime.UtcNow,
IsPersistent = true
}, newIdentity);
newIdentity 是您的声明身份,希望这会有所帮助。
推荐阅读
- python - 在没有 Internet 的情况下安装 python 库依赖项
- java - 查找一个点是否在多边形内 - JAVA jts / awt / geotools
- r - 聚合数据的人口统计数据包问题
- javascript - 节点上的自动化事件是否在节点断开时取消?
- angular - 如何在所有对象的数组中显示特定字段
- .net - JSON 反序列化为接口
- python - 从 .pdf 中提取粗体和带下划线的文本
- java - 如何显示当前用户数据?
- excel - Apache POI 可以提取工作表的唯一重命名友好“代码名”值吗?
- c# - EF Core 2.1.4 Include 正在对可选关系执行 INNER JOIN