当前位置: 首页 > 知识库问答 >
问题:

IdentityServer4-在遵循混合MVC快速启动后使用刷新令牌

秦哲瀚
2023-03-14

我遵循了文档页面中的快速启动,使用IdentityServer进行身份验证,对三个服务(IdentityServer、一个Api服务、一个ASPNET MVC应用程序)进行了有效配置。

一切工作都很完美(登录、登录、授权等),直到access_token过期1小时后。此时,MVC应用程序开始从应用编程接口服务接收(正确地)401(因为令牌过期了)。那时,我知道我应该使用refresh_token来获得新的access_token。

我在寻找一种自动刷新access_令牌的机制,但无意中发现了:https://github.com/mderriey/TokenRenewal/blob/master/src/MvcClient/Startup.cs(来自这个答案)。我试图使用它,但没有成功(即使身份验证成功,TokenEndpointResponse也为空)。

我知道如何使用refresh_token来获取新的access_token,但在我拥有它之后,我该如何将其插入到cookie中,以便将来的请求能够访问新的token?

共有3个答案

方韬
2023-03-14

首先,确保使用IdentityModel库(nuget-it)。第二,由于Auth 2.0已经发布,因此出现了一些突破性的更改和HttpContext。Rafaels解决方案中使用的身份验证现在已经过时。下面是应该进行的更改,以使其重新作为过滤器运行

var expat = filterContext.HttpContext.Authentication.GetTokenAsync("expires_at").Result;

应该成为:

var expat = filterContext.HttpContext.GetTokenAsync("expires_at").Result;
var rt = filterContext.HttpContext.Authentication.GetTokenAsync("refresh_token").Result;

应该成为:

var rt = filterContext.HttpContext.GetTokenAsync("refresh_token").Result;
var oldIdToken = filterContext.HttpContext.Authentication.GetTokenAsync("id_token").Result;

应该成为

var oldIdToken = filterContext.HttpContext.GetTokenAsync("id_token").Result;
var info = filterContext.HttpContext.Authentication.GetAuthenticateInfoAsync("Cookies").Result;

应该成为

var info = filterContext.HttpContext.AuthenticateAsync("Cookies").Result;
filterContext.HttpContext.Authentication.SignInAsync("Cookies", info.Principal, info.Properties);

应该成为

filterContext.HttpContext.SignInAsync("Cookies", info.Principal, info.Properties);

这是一个完整的代码:

public class TokenFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var expat = filterContext.HttpContext.GetTokenAsync("expires_at").Result;

        var dataExp = DateTime.Parse(expat, null, DateTimeStyles.RoundtripKind);

        if ((dataExp - DateTime.Now).TotalMinutes < 10)
        {
            var disco = DiscoveryClient.GetAsync("http://localhost:5000/").Result;
            if (disco.IsError) throw new Exception(disco.Error);

            var tokenClient = new TokenClient(disco.TokenEndpoint, "clientId",
            "clientSecret");

            var rt = filterContext.HttpContext.GetTokenAsync("refresh_token").Result;
            var tokenResult = tokenClient.RequestRefreshTokenAsync(rt).Result;

            if (!tokenResult.IsError)
            {
                var oldIdToken = filterContext.HttpContext.GetTokenAsync("id_token").Result;
                var newAccessToken = tokenResult.AccessToken;
                var newRefreshToken = tokenResult.RefreshToken;

                var tokens = new List<AuthenticationToken>
                {
                    new AuthenticationToken {Name = OpenIdConnectParameterNames.IdToken, Value = oldIdToken},
                    new AuthenticationToken
                    {
                        Name = OpenIdConnectParameterNames.AccessToken,
                        Value = newAccessToken
                    },
                    new AuthenticationToken
                    { 
                        Name = OpenIdConnectParameterNames.RefreshToken,
                        Value = newRefreshToken
                    }
                };

                var expiresAt = DateTime.Now + TimeSpan.FromSeconds(tokenResult.ExpiresIn);
                tokens.Add(new AuthenticationToken
                {
                    Name = "expires_at",
                    Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
                });

                var info = filterContext.HttpContext.AuthenticateAsync("Cookies").Result;
                info.Properties.StoreTokens(tokens);  
                filterContext.HttpContext.SignInAsync("Cookies", info.Principal, info.Properties);
            }
        }
    }
}

美国和拉斐尔的表现是一样的。

终安和
2023-03-14

作为MVC客户机示例中更新Tokens方法的一个选项,我制作了一个过滤器,当token大约10分钟或更短的时间到期时,它会自动生成作业。

public class TokenFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var expat = filterContext.HttpContext.Authentication.GetTokenAsync("expires_at").Result;

        var dataExp = DateTime.Parse(expat, null, DateTimeStyles.RoundtripKind);

        if ((dataExp - DateTime.Now).TotalMinutes < 10)
        {
            var disco = DiscoveryClient.GetAsync("http://localhost:5000/").Result;
            if (disco.IsError) throw new Exception(disco.Error);

            var tokenClient = new TokenClient(disco.TokenEndpoint, "clientId",
                "clientSecret");

            var rt = filterContext.HttpContext.Authentication.GetTokenAsync("refresh_token").Result;
            var tokenResult = tokenClient.RequestRefreshTokenAsync(rt).Result;

            if (!tokenResult.IsError)
            {
                var oldIdToken = filterContext.HttpContext.Authentication.GetTokenAsync("id_token").Result;
                var newAccessToken = tokenResult.AccessToken;
                var newRefreshToken = tokenResult.RefreshToken;

                var tokens = new List<AuthenticationToken>
                {
                    new AuthenticationToken {Name = OpenIdConnectParameterNames.IdToken, Value = oldIdToken},
                    new AuthenticationToken
                    {
                        Name = OpenIdConnectParameterNames.AccessToken,
                        Value = newAccessToken
                    },
                    new AuthenticationToken
                    {
                        Name = OpenIdConnectParameterNames.RefreshToken,
                        Value = newRefreshToken
                    }
                };

                var expiresAt = DateTime.Now + TimeSpan.FromSeconds(tokenResult.ExpiresIn);
                tokens.Add(new AuthenticationToken
                {
                    Name = "expires_at",
                    Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
                });

                var info = filterContext.HttpContext.Authentication.GetAuthenticateInfoAsync("Cookies").Result;
                info.Properties.StoreTokens(tokens);
                filterContext.HttpContext.Authentication.SignInAsync("Cookies", info.Principal, info.Properties);
            }
        }
    }
}

用法:

[Authorize]
[TokenFilter]
public class HomeController : Controller
{}
华宇
2023-03-14

McvHyamp示例提供了一个很好的示例,可以将新的access_tokenrefresh_token返回主体。这里有一个带有代码的github文件的链接,位于RenewTokens()中,如下所示。

    public async Task<IActionResult> RenewTokens()
    {
        var disco = await DiscoveryClient.GetAsync(Constants.Authority);
        if (disco.IsError) throw new Exception(disco.Error);

        var tokenClient = new TokenClient(disco.TokenEndpoint, "mvc.hybrid", "secret");
        var rt = await     HttpContext.Authentication.GetTokenAsync("refresh_token");
        var tokenResult = await tokenClient.RequestRefreshTokenAsync(rt);

        if (!tokenResult.IsError)
        {
            var old_id_token = await HttpContext.Authentication.GetTokenAsync("id_token");
            var new_access_token = tokenResult.AccessToken;
            var new_refresh_token = tokenResult.RefreshToken;

            var tokens = new List<AuthenticationToken>();
            tokens.Add(new AuthenticationToken { Name = OpenIdConnectParameterNames.IdToken, Value = old_id_token });
            tokens.Add(new AuthenticationToken { Name = OpenIdConnectParameterNames.AccessToken, Value = new_access_token });
            tokens.Add(new AuthenticationToken { Name = OpenIdConnectParameterNames.RefreshToken, Value = new_refresh_token });

            var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn);
            tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) });

            var info = await HttpContext.Authentication.GetAuthenticateInfoAsync("Cookies");
            info.Properties.StoreTokens(tokens);
            await HttpContext.Authentication.SignInAsync("Cookies", info.Principal, info.Properties);

            return Redirect("~/Home/Secure");
        }

        ViewData["Error"] = tokenResult.Error;
        return View("Error");
    }
 类似资料:
  • 我正在使用.NET的MirrorQuickStart项目,遇到了刷新令牌的问题。据我所知,当“notify”操作用于时间线订阅更新时,它不会被使用。 将应用程序发布到开发服务器上,除了更新适当的ID和配置信息之外,基本上是原样的,“Notify”操作在第一个小时内工作,但之后,它停止响应,直到我刷新web页面并重新进行身份验证。 我检查了数据库服务器上的StoredCredentials表,并填充

  • 问题内容: 我有我的.. 我加入的一个。当页面内容为屏幕时,它起作用。但是当我没有收到太多数据并且不是时,就会出现问题,该功能无法正常工作。:( 我没有使用。 有人可以帮我解决这个问题吗? 问题答案: var alwaysBounceVertical:Bool //默认为NO。如果是,并且反弹为是,即使内容小于界限,也允许垂直拖动

  • 问题内容: Python的urllib2遵循3xx重定向以获取最终内容。有没有办法使urllib2(或其他一些库,例如httplib2)也遵循元刷新?还是我需要为刷新meta标签手动解析HTML? 问题答案: 好的,似乎没有库支持它,因此我一直在使用以下代码:

  • 我用IdentityServer4创建了一个令牌我复制了这个例子我只是修改了这个 在身份服务器中- 我的令牌应该在10秒后到期,并且每10秒我有一个刷新令牌,但我不知道如何测试它。我做类似的事情: 它退回已过期的商品,我认为它应该退回我未过期的商品,因为它会被刷新。

  • Swoole的绝大部分功能只能用于cli命令行环境,请首先准备好Linux Shell环境。可使用vim、emacs、phpstorm或其他编辑器编写代码,并在命令行中通过下列指令执行程序。 php /path/to/your_file.php 成功执行Swoole服务器程序后,如果你的代码中没有任何echo语句,屏幕不会有任何输出,但实际上底层已经在监听网络端口,等待客户端发起连接。可使用相应的

  • 我试图理解谷歌GCM快速入门示例背后的代码。具体来说,我不明白代码是如何检查注册是否已经完成的。 主要活动: 注册意向服务: 在中,注释说最初调用是为了检索令牌,但随后的调用是本地的。这是否意味着它会简单地检查应用程序是否已经拥有令牌,不再进行调用?我真的不明白这部分,我在这个示例代码中没有看到它检查令牌存在的任何地方。