如何为使用外部提供程序登录的用户生成AccessToken

时间:2017-07-04 14:17:52

标签: asp.net-core openid openid-connect openiddict google-openidconnect

我有一个由asp.net核心实现的API。 我已经使用OpenIddict为通过电子邮件和密码注册到我的api的用户生成访问令牌和刷新令牌。 我已将Google中间件(.UseGoogleAuthentication ...)添加到我的API中,我可以使用Google成功登录用户。 我的客户端是UWP,我使用WebAuthenticationBroker将reestst发送到localhost / Account / ExternalLogin / Google后重定向到谷歌。 当用户使用google登录时,他被重定向到Account / ExternalLoginConfirmation,这对于现在完成ExternalLoginConfirmation之前的这一点是微不足道的我想要为WebAuthenticationBroker关闭时为用户生成并发回一个访问令牌和刷新令牌我没有其他办法为这个用户获取令牌(因为他没有密码,我不知道用户名)。 我试过这个:

//
    // 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

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

1 个答案:

答案 0 :(得分:0)

  

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

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

要使您的方案有效,您必须使用所有OpenID Connect参数将用户重定向回授权端点。

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