尝试与ASP Web API和OWIN中的Google Auth_code获取Access_Token时无效的赠品



我正在为我们的移动应用程序客户开发Google sue服务中的Google签名。我们的服务位于Dotnet平台(ASP.NET Web API)上,我们的身份验证处理程序与Owin一起是ASP身份,因为它的中间软件。我们的客户使用本地Google库通过Google(用于身份验证)和最后,当用户通过Google进行身份验证时,Google返回了回调事件中的两个重要值,这些值是" ID_TOKEN" " auth_code"

正如我之前读过的(https://developers.google.com/inentity/sign-in/android/android/offline-access ), auth_code 应该 hop with with access_token access_token 应为给定为了访问授权资源。

当我想与Access_Token交换Auth_code(由客户端发送)时,我将使用以下请求参数拨打Owin代币端点

  • grant_type(授权_code)
  • 代码
  • client_id
  • client_secret请注意,由于我的客户是移动应用程序,我不发送redirect_uri参数

我的响应始终是" Invalid_grant" >但是,当我向Google令牌端点发送完全相同的请求(使用相同的数据)时,它(Google token endpoint)很容易使我访问访问诸如到期之类的数据),因此我的请求参数是正确的,但我不知道为什么我无法从我自己的本地服务获得access_token

这是我的要求正文的样本:grant_type = pretureization_code& code = auth_code& client_id = myclientid.apps.googleusercontent.com& client_secret = myclextecret

>

我还为"授权的JavaScript Origins"one_answers"授权重定向URIS"字段设置了Localhost Web API URL

我想我错过了一些东西(也许是在我的配置中)。
这可能是因为我的API代码未部署在公共领域上,如果这样,为什么Google SSO流程仍然适用于Web客户端的Localhost(即使我在Google Console中指定了Localhost)

请注意,我仅适用于移动应用客户端,Web客户端,Google Oauth,ASP Identity和Owin的集成像Magic一样工作,因为在Google回到指定的Redirect_uri中,Google将Access_Token作为查询字符串参数(否)需要将auth_code传递到API服务器以获取access_token)。

这是我在startup.cs文件中的GoogleOauth配置

 app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
        };
        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);
        // Uncomment the following lines to enable logging in with third party login providers
        //app.UseMicrosoftAccountAuthentication(
        //    clientId: "",
        //    clientSecret: "");
        //app.UseTwitterAuthentication(
        //    consumerKey: "",
        //    consumerSecret: "");
        //app.UseFacebookAuthentication(
        //    appId: "",
        //    appSecret: "");
        app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
        {
            ClientId = "MYCLIENTID.apps.googleusercontent.com",
            ClientSecret = "MYCLIENTSECRET"

        });

我一直在这个问题上拉头发,任何帮助都将不胜感激

我没有找到解决问题的方法>

Google SSO的客户端SDK(Android,iOS等)具有相同的机制,当用户成功地登录Google并返回App Google SDK返回一次使用给客户的client token,称为 Auth Code ,如果将此代码发送到Google OAuth2 API终点(https://accounts.google.com/o/oauth2/token),则使用以下格式$"grant_type=authorization_code&code={YOUR AUTH CODE}&client_id={YOUR CLIENT ID (set in google dev console)}&client_secret={YOUR CLIENT SECRET (set in google dev console)}"您会收到一个访问令牌,您可以访问Google Services(Google drive,gmail,gmail,gmail,gmail,gmail,gmail,gmail,gmail,gmailETC)。

因此,您可以直接调用该API(使用httpclient),如果您收到该access_token,则表明用户已成功登录到Google,因此您可以检查他们在本地DB中是否有帐户,请通过调用<来登录它们>您的本地令牌端点,否则注册用户(使用默认密码),然后调用您的令牌端点(我知道在API应用程序中调用您的API端点有点脏,但是您知道我的情况,因为没有人回答这个问题,所以我别无选择)

这是我的代码

在我的帐户控制器中

 [AllowAnonymous]
    public async Task<ActionResult> LoginWithGoogle(string email, string ac)
    {
        var appType = StoreContext.GetApplicationType();
        var requestStoreFrontType = Request.Headers["StoreFrontType"];
        #region removing mobile header (for google)
        //if not removing, google Api will reject our request
        Request.RemoveHeaderIfExist("StoreFrontType");
        Request.RemoveHeaderIfExist("StoreFrontVersion");
        Request.RemoveHeaderIfExist("Client_Token");
        Request.RemoveHeaderIfExist("Content-Type");
        #endregion
        var _googleService = new GoogleExternalLoginService();
        var registerResult = _googleService.LoginExternal(ac, appType);
        if (registerResult.Status == ServiceResultStatus.Success)
        {
            var pass = defaultPass;
            var registermodel = new RegisterViewModel();
            registermodel.AcceptPolicy = true;
            registermodel.Email = email;
            registermodel.EnableNewsLetter = true;
            registermodel.Password = pass;
            string getTokenUrl = "";
        var existedUser = UserManager.FindByEmail(registermodel.Email);
            if (existedUser == null)
            {
                var owinUser = new ApplicationUser { UserName = email, Email = email, RegistrationType = GetUserRegTypeByExternalProviderName("Google") };
                    var result = await UserManager.CreateAsync(owinUser, registermodel.Password);
                    if (!result.Succeeded)
                        return new DSJson(null, registerResult.Message, registerResult.Status);
                getTokenUrl = Request.Url.Scheme + "://" + Request.Url.Authority 
                    +"/Token";
            }
            else
            {
                ECS.Cache.CacheFacade.Store(ac, email, DateTime.Now.AddMinutes(2));
                getTokenUrl = Request.Url.Scheme + "://" + Request.Url.Authority
                              + "/Token" + $"?IsSSO=1&AuthCode={ac}";
            }
            var getTokenParams = new List<KeyValuePair<string, string>>();
            getTokenParams.Add(new KeyValuePair<string, string>("grant_type", "password"));
            getTokenParams.Add(new KeyValuePair<string, string>("username", registermodel.Email));
            getTokenParams.Add(new KeyValuePair<string, string>("password", registermodel.Password));
            var headers = new Dictionary<string, string>();
            //headers.Add("StoreFrontType", StoreContext.StoreFrontType);
            //headers.Add("StoreFrontVersion", StoreContext.StoreFrontVersion);
            //headers.Add("Client_Token", StoreContext.ClientToken);
            var tokenResponse = HttpHelper.CallService<object>(getTokenUrl, "Post", null, getTokenParams.ToArray(), headers).Data;
            return new DSJson(tokenResponse, isResultDataInServiceResult: true);
        }
        return new DSJson(null, "operation failed, auth_code is invalid", ServiceResultStatus.Fail);
    }

请注意,在您的请求中有任何额外的自定义标头时,我必须在将请求发送到Google Endpoint之前,在将请求发送到Google端点之前必须删除所有客户的标题。

这是我在操作中使用的loginexternal方法代码

 public ServiceResult<ExternalTokenView> LoginExternal(string requestCode,ApplicationType appType)
    {
        var res = new ServiceResult<ExternalTokenView>();
        var getTokenParams = new List<KeyValuePair<string, string>>();
        getTokenParams.Add(new KeyValuePair<string, string>("grant_type", "authorization_code"));
        getTokenParams.Add(new KeyValuePair<string, string>("code", requestCode));
        getTokenParams.Add(new KeyValuePair<string, string>("client_id", ClientIds[appType.ToString()]));
        if (appType == ApplicationType.AppAndroid)
            getTokenParams.Add(new KeyValuePair<string, string>("client_secret", ClientSecrets[appType.ToString()]));
        var getTokenUrl = TokenEndpoint;
        var response = HttpHelper.CallService<ExternalTokenView>(getTokenUrl, "Post", null, rowData: getTokenParams.ToArray());
        res.Data = response.Data;
        res.Status = response.Status;
        return res;
    }

请注意,对于iOS客户端,您不应该发送客户端秘密(仅适用于Android客户端)。

最后,这是我的令牌端点代码

 public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
        ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
        if (user == null)
        {
            // برای کاربرانی که قبلا اکانت داشته اند که پسوردشان متفاوت با پسورد پیش فرض برای 
            //external logins
            //است
            if (!string.IsNullOrEmpty(HttpContext.Current.Request["IsSSO"]))
            {
                var authCode = HttpContext.Current.Request["AuthCode"];
                if (!string.IsNullOrEmpty(authCode))
                {
                    var emailInCache = ECS.Cache.CacheFacade.Get<string>(authCode);
                    if (!string.IsNullOrEmpty(emailInCache))
                    {
                        user = await userManager.FindByEmailAsync(emailInCache);
                        Cache.CacheFacade.Remove(authCode);
                    }
                }
            }
            else
            {
                context.SetError("invalid_grant", "ایمیل/موبایل یا رمز عبور نا معتبر است");
                return;
            }
        }
        ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
           OAuthDefaults.AuthenticationType);
        ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
            CookieAuthenticationDefaults.AuthenticationType);
        AuthenticationProperties properties = CreateProperties(user.UserName);
        properties.Dictionary.Add(new KeyValuePair<string, string>("UserRegisterationType",((byte)user.RegistrationType).ToString()));
        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
        context.Validated(ticket);
    }

您可能已经注意到我将authcode值存储在LoginWithGoogle操作中,并在GrantResourceOwnerCredentials方法中读取CACHE的值,以便在我们没有密码时能够授予用户令牌Gmail帐户)。但是,从缓存中读取Auth代码的原因是,例外过程只能用于来自Google和其他用户必须通过正常过程(使用其用户名和密码的代币)

>的流程。

希望它有帮助

相关内容

  • 没有找到相关文章

最新更新