如何为使用外部提供商登录的用户生成AccessToken [英] How to Generate AccessToken for user who is logged in with External Providers

查看:200
本文介绍了如何为使用外部提供商登录的用户生成AccessToken的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由asp.net核心实现的API. 我已经使用OpenIddict为通过电子邮件和密码注册到我的api的用户生成访问令牌和刷新令牌. 我已将Google中间件(.UseGoogleAuthentication ...)添加到我的API中,并且可以成功使用Google登录用户. 我的客户端是UWP,在将请求发送到localhost/Account/ExternalLogin/Google之后,我使用WebAuthenticationBroker将其重定向到google. 当用户使用google登录时,他被重定向到Account/ExternalLoginConfirmation,这很简单,直到用ExternalLoginConfirmation完成之前,如果WebAuthenticationBroker关闭,我想为用户生成并发送回访问令牌和刷新令牌,这是很重要的我没有其他方法可以为该用户获取令牌(因为他没有密码,并且用户名对我来说是未知的). 重复这个:

I have an API implemented by asp.net core. I've used OpenIddict to generate access token and refresh token for users who registered to my api by email and password. I've added Google middleware (.UseGoogleAuthentication ... ) to my API and I can successfully log in user with Google. My client is UWP and I use WebAuthenticationBroker to get redirected to google after sending a reuest to localhost/Account/ExternalLogin/Google. when the users is logged In with google he is redirected to Account/ExternalLoginConfirmation which is trivial to this point now before it finishes with ExternalLoginConfirmation I Want to generate and send back an Access Token and a refresh token for the user cause if the WebAuthenticationBroker get's closed I have no other way to get tokens for this user(cause he has no password and the username will be unknown to me). Itried this :

//
    // POST: /Account/ 
    [HttpPost("ExternalLoginConfirmation")]
    [AllowAnonymous]
    //[ValidateAntiForgeryToken]
    public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model,
        string returnUrl = null)
    {
        if (ModelState.IsValid)
        {
            // Get the information about the user from the external login provider
            var info = await SignInManager.GetExternalLoginInfoAsync();
            if (info == null)
                return View("ExternalLoginFailure");
            var user = new UserInfo { UserName = model.Email, Email = model.Email };
            var result = await UserManager.CreateAsync(user);
            if (result.Succeeded)
            {
                result = await UserManager.AddLoginAsync(user, info);
                if (result.Succeeded)
                {
                    await SignInManager.SignInAsync(user, false);
                    Logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
                    var identity = new ClaimsIdentity(
                OpenIdConnectServerDefaults.AuthenticationScheme,
                OpenIdConnectConstants.Claims.Name, null);

                    // Add a "sub" claim containing the user identifier, and attach
                    // the "access_token" destination to allow OpenIddict to store it
                    // in the access token, so it can be retrieved from your controllers.
                    identity.AddClaim(OpenIdConnectConstants.Claims.Subject,
                        user.Id,
                        OpenIdConnectConstants.Destinations.AccessToken);

                    identity.AddClaim(OpenIdConnectConstants.Claims.Name, user.UserName,
                        OpenIdConnectConstants.Destinations.AccessToken);

                    // ... add other claims, if necessary.

                    var principal = new ClaimsPrincipal(identity);

                    var authenticateInfo = await HttpContext.Authentication.GetAuthenticateInfoAsync(info.LoginProvider);
                    var ticket = CreateTicketAsync(principal, authenticateInfo.Properties);

                    // Ask OpenIddict to generate a new token and return an OAuth2 token response.
                    return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
                    //return RedirectToLocal(returnUrl);
                }
            }
            AddErrors(result);
        }

        //ViewData["ReturnUrl"] = returnUrl;
        return BadRequest();
    }

    #region _helpers

    private AuthenticationTicket CreateTicketAsync(ClaimsPrincipal principal,
        AuthenticationProperties properties = null)
    {
        // Create a new authentication ticket holding the user identity.
        var ticket = new AuthenticationTicket(principal, properties,
            OpenIdConnectServerDefaults.AuthenticationScheme);

       ticket.SetScopes(new[]
       {
           /* openid: */ OpenIdConnectConstants.Scopes.OpenId,
           /* email: */ OpenIdConnectConstants.Scopes.Email,
           /* profile: */ OpenIdConnectConstants.Scopes.Profile,
           /* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess,
           /* roles: */ OpenIddictConstants.Scopes.Roles
       });

        ticket.SetAudiences(Configuration["Authentication:OpenIddict:Audience"]);

        return ticket;
    }

    private void AddErrors(IdentityResult result)
    {
        foreach (var error in result.Errors)
            ModelState.AddModelError(string.Empty, error.Description);
    }

    private IActionResult RedirectToLocal(string returnUrl)
    {
        if (Url.IsLocalUrl(returnUrl))
            return Redirect(returnUrl);
        return BadRequest();
    }

    #endregion

但这失败并引发异常: an authorization or token response cannot be returned from this controller

but this fails and throws exception : an authorization or token response cannot be returned from this controller

现在如何为用户生成这些令牌?

now how do I generate these Tokens for the user?

推荐答案

现在如何为用户生成这些令牌?

now how do I generate these Tokens for the user?

OpenIddict故意阻止您从非OIDC端点返回OIDC响应(出于明显的安全原因).

OpenIddict deliberately prevents you from returning OIDC responses from non-OIDC endpoints (for obvious security reasons).

要使您的方案正常工作,必须使用所有OpenID Connect参数将用户重定向回授权端点.

To make your scenario work, you must redirect your users back to the authorization endpoint with all the OpenID Connect parameters.

具体来说,您应该还原添加到ExternalLoginConfirmation()的所有更改(应该返回RedirectToLocal(returnUrl);),并将SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);部分移回授权控制器.

Concretely, you should revert all the changes added to ExternalLoginConfirmation() (that should return RedirectToLocal(returnUrl);) and move the SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme); part back to your authorization controller.

这篇关于如何为使用外部提供商登录的用户生成AccessToken的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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