ASP.NET Identity(与IdentityServer4一起)获取外部资源oauth访问令牌 [英] ASP.NET Identity (with IdentityServer4) get external resource oauth access token

查看:190
本文介绍了ASP.NET Identity(与IdentityServer4一起)获取外部资源oauth访问令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经通过了IdentityServer4的文档,并将其设置为使用Microsoft Office 365作为登录提供程序.用户登录后,我想创建一个按钮,使他可以使用graph.microsoft.com的webhooks api允许我的应用订阅他的日历事件

I have been through the docs of identityServer4 and I have set it up to use Microsoft Office 365 as a login provider. When the user has logged in I want to make a button where he can allow my app to subscribe to his calendar events using the webhooks api of graph.microsoft.com

startup.cs中的代码

The code in startup.cs

app.UseMicrosoftAccountAuthentication(new MicrosoftAccountOptions
{
     AuthenticationScheme = "Microsoft",
     DisplayName = "Microsoft",
     SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme,

     ClientId = "CLIENT ID",
     ClientSecret = "CLIENT SECRET",
     CallbackPath = new PathString("/signin-microsoft"),
     Events = new OAuthEvents
     {
         OnCreatingTicket = context =>
         {
             redisCache.Set("AccessToken", context.AccessToken.GetBytes(), new DistributedCacheEntryOptions
             {
                 AbsoluteExpiration = DateTimeOffset.UtcNow.AddDays(3)
             });
             return Task.FromResult(context);
         }
     }
     Scope =
     {
         "Calendars.Read",
         "Calendars.Read.Shared",
     },
     SaveTokens = true
});

但这显然不是一条可行的道路.我这样做只是出于测试目的,并为所需的订阅进行了PoC.

But this is obviously not a viable path to go. I have only done this for testing purposes and to make a PoC of the subscriptions needed.

现在,我想知道是否有一种更智能的方法与IdentityServer通信,该方法可以让我获取此外部访问令牌,以便我可以代表已登录的用户使用Microsoft api?

Now I would like to know if there is a smarter way to communicate with the identityServer that allows me to get this external access token, so that I can use the microsoft api on behalf of my logged in users?

还是我唯一的选择是直接从此OAuthEvent中获取Microsoft AccessToken并将其直接存储在与登录用户链接的数据库中?

Or is my only option to take the Microsoft AccessToken directly from this OAuthEvent and store it directly in a database, linked to the logged in user?

我真的需要这个,因为我的大部分功能都是基于第三方的数据.

I really need this, since most of my functionality is based on data from third parties.

推荐答案

好,所以我终于开始工作了.我创建了一个使用ASP.Net IdentityIdentityServer4都在ASP.Net Core之上的新项目.

Ok, so I finally got this working. I have created a new project that is using ASP.Net Identity and IdentityServer4 both build on top of ASP.Net Core.

问题是我不完全了解外部登录过程中使用的流程.

The problem was that I wasn't completely aware of the flow that was used in the external login process.

如果同时使用两个系统的样板,则会出现AccountController,其中将显示以下方法:

If you use the boiler plates from both systems you will have an AccountController where the following method will be present:

//
// GET: /Account/ExternalLoginCallback
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
    if (remoteError != null)
    {
        ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
        return View(nameof(Login));
    }
    var info = await _signInManager.GetExternalLoginInfoAsync();
    if (info == null)
    {
        return RedirectToAction(nameof(Login));
    }

    // Sign in the user with this external login provider if the user already has a login.
    var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
    if (result.Succeeded)
    {
        await _signInManager.UpdateExternalAuthenticationTokensAsync(info);

        _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
        return RedirectToLocal(returnUrl);
    }
    if (result.RequiresTwoFactor)
    {
        return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
    }
    if (result.IsLockedOut)
    {
        return View("Lockout");
    }
    else
    {
        // If the user does not have an account, then ask the user to create an account.
        ViewData["ReturnUrl"] = returnUrl;
        ViewData["LoginProvider"] = info.LoginProvider;
        var email = info.Principal.FindFirstValue(ClaimTypes.Email);
        return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
    }
}

这里的重要部分是:

await _signInManager.UpdateExternalAuthenticationTokensAsync(info);

这会将您的外部凭据保存在与ASP.Net identity关联的数据库表中.在表AspNetUserTokens中,您现在将有3个条目,称为: access_tokenexpires_attoken_type.

This will save your external credentials in the database table associated with your ASP.Net identity. In the table AspNetUserTokens you will now have 3 entries, called something like: access_token, expires_at and token_type.

这些是我们感兴趣的令牌,可用于访问应用程序中其他位置的用户凭据.

These are the tokens that we are interested in, that we can use to access the users credentials somewhere else in our application.

要在已登录用户的上下文中获取这些令牌:

To fetch these tokens in the context of a logged in user:

var externalAccessToken = await _userManager.GetAuthenticationTokenAsync(User, "Microsoft", "access_token");

要为我们从数据库中获取的用户获取它们,我们可以使用:

And to fetch them for a user we fetch from the DB we can use:

var user = _userManager.Users.SingleOrDefault(x => x.Id == "myId");
if (user == null)
    return;

var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
var externalAccessToken = await _userManager.GetAuthenticationTokenAsync(claimsPrincipal, "Microsoft", "access_token");

这篇关于ASP.NET Identity(与IdentityServer4一起)获取外部资源oauth访问令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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