拥有新的access_token后,如何更新我的cookie? [英] How do I update my cookie, having got a new access_token?

查看:137
本文介绍了拥有新的access_token后,如何更新我的cookie?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用刷新令牌获取新的访问令牌后,我想使用该访问令牌更新客户端Cookie.

我的客户端能够使用ajax登录并调用我的REST API,但是当该第一授权到期时,该API调用自然将不再起作用.

我有一个使用自己的REST API的.NET Web应用程序.该API是同一项目的一部分.它没有自己的启动配置.

在每个请求的标头中发送cookie时,它需要具有新的未过期的访问令牌,这样我才不会收到该请求的用户未授权".

现在,我可以使用刷新令牌来获取新令牌,但是cookie的值没有更改,因此,我相信我需要在客户端发送任何请求之前更新cookie以反映新的访问令牌. /p>

以下是我的混合客户端:

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是您的声明身份,希望对您有所帮助.

Having used a refresh token to get a new access token, I want to update my client side cookie with that access token.

My client is able to sign in and call my REST API using ajax, however when that first authorization expires, naturally the API calls no longer work.

I have a .NET web application which consumes its own REST API. The API is a part of the same project. It does not have its own startup configuration.

As the cookie is being sent in the header of each request it needs to have the new unexpired access token so that I don't get 'User unauthorized' for the request.

Right now I am able to get a new token using my refresh token but the value of the cookie has not changed, so I believe I need to update my cookie to reflect the new access token before the client sends any requests.

Here's a look at my hybrid client:

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);
                        }
                    }
                }
            });
        }
    }
}

I've looked into a lot of things but the value of my cookie always stays the same. I've considered deleting the old cookie and just building the new cookie manually, but that requires encrypting it the right way and it smells funny, surely not the idiomatic way to do it.

I feel there must be something simple I am missing. I would expect a simple "UpdateCookie(newToken)" kind of method and I have tried SignIn() and SignOut() but these have not worked out for me, seemingly not interacting with the cookie at all in fact.

解决方案

This is how I got mine to work, add the following lines:

SecurityTokenValidated = context =>
                        {
                            context.AuthenticationTicket.Properties.AllowRefresh = true;
                            context.AuthenticationTicket.Properties.IsPersistent = true;
                        }

Then in AuthorizationCodeReceived add this to the end:

HttpContext.Current.GetOwinContext().Authentication.SignIn(new AuthenticationProperties
                                    {
                                        ExpiresUtc = DateTimeOffset.UtcNow.AddSeconds(tokenResponse.ExpiresIn),
                                        AllowRefresh = true,
                                        IssuedUtc = DateTime.UtcNow,
                                        IsPersistent = true
                                    }, newIdentity);

Where newIdentity is your claims identity, hope this helps.

这篇关于拥有新的access_token后,如何更新我的cookie?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆