23

Google を外部ログイン プロバイダとして使用する際に断続的に発生する問題を修正しようとしています。

ログインしようとすると、ユーザーは認証されるのではなく、ログイン ページにリダイレクトされます。

問題はこの行 (以下のリンクの 55 行目) で発生し、GetExternalIdentityAsync は null を返します。

var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);

完全なコードは次のとおりです。

[Authorize]
public abstract class GoogleAccountController<TUser> : Controller where TUser : Microsoft.AspNet.Identity.IUser
{
    public IAuthenticationManager AuthenticationManager
    {
        get
        {
            return HttpContext.GetOwinContext().Authentication;
        }
    }

    public abstract UserManager<TUser> UserManager { get; set; }

    [AllowAnonymous]
    [HttpGet]
    [Route("login")]
    public ActionResult Login(string returnUrl)
    {
        ViewData.Model = new LoginModel()
        {
            Message = TempData["message"] as string,
            Providers = HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes(),
            ReturnUrl = returnUrl
        };

        return View();
    }

    [AllowAnonymous]
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Route("login")]
    public ActionResult Login(string provider, string returnUrl)
    {
        return new ChallengeResult(provider, Url.Action("Callback", "Account", new { ReturnUrl = returnUrl }));
    }

    [AllowAnonymous]
    [Route("authenticate")]
    public async Task<ActionResult> Callback(string returnUrl)
    {
        var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);

        if (externalIdentity == null)
        {
            return RedirectToAction("Login", new { ReturnUrl = returnUrl });
        }

        var emailAddress = externalIdentity.FindFirstValue(ClaimTypes.Email);
        var user = await UserManager.FindByNameAsync(emailAddress);

        if (user != null)
        {
            await SignInAsync(user, false);

            return RedirectToLocal(returnUrl);
        }
        else
        {
            TempData.Add("message", string.Format("The account {0} is not approved.", emailAddress));

            return RedirectToAction("Login", new { ReturnUrl = returnUrl });
        }
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Route("logout")]
    public ActionResult Logout(string returnUrl)
    {
        AuthenticationManager.SignOut();

        return RedirectToLocal(returnUrl);
    }

    private async Task SignInAsync(TUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

        var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
        var authenticationProperties = new AuthenticationProperties()
        {
            IsPersistent = isPersistent
        };

        AuthenticationManager.SignIn(authenticationProperties, identity);
    }

    private ActionResult RedirectToLocal(string returnUrl)
    {
        if (Url.IsLocalUrl(returnUrl))
        {
            return Redirect(returnUrl);
        }
        else
        {
            return RedirectToAction("Index", "Home");
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing && UserManager != null)
        {
            UserManager.Dispose();
            UserManager = null;
        }

        base.Dispose(disposing);
    }
}

ここにもあります。

これは非常に断続的な問題であり、アプリを再デプロイすると一時的に動作するようになることがよくあります。

Fiddler を見ると、Cookie が見つからない認証メソッドの直前で sign-google への呼び出しが行われていることがわかります。

フィドラーのスクリーンショット

アプリは次のコードを使用して、Google ログインを初期化します。

app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/login")
    });
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseGoogleAuthentication();

web.config で認証モードを非に設定し、フォーム認証モジュールを削除しました。

<system.web>
    <authentication mode="None" />
</system.web>    
<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />    
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="FormsAuthenticationModule" />
    </modules>
</system.webServer>

サイトは Azure でホストされており、1 つのインスタンスで実行されているものもあれば、2 つのインスタンスで実行されているものもあります。

なぜこれが起こっているのか、誰でも助けてもらえますか?

アップデート

Microsoft.Owin.Security.Google のバージョン 3.0 が昨夜リリースされました。切り替えて、これで問題が解決するかどうかを確認します。

https://www.nuget.org/packages/Microsoft.Owin.Security.Google

4

7 に答える 7

2

Microsoft の System.Web の Owin 実装にはバグがあります。IIS で Owin アプリケーションを実行するときに使用されているもの。ASP.NET MVC5 で新しい Owin ベースの認証処理を使用している場合、おそらく 99% の人がそうしています。

このバグにより、Owin によって設定された Cookie が不思議なことに消えてしまうことがあります。

このナゲットをhttps://github.com/KentorIT/owin-cookie-saverの前に 置きますapp.UseGoogleAuthentication(...)

于 2016-12-31T20:55:20.433 に答える
2

Google 開発者コンソールで「Google + API」を有効にするのを忘れていました。Google ログインは問題ないように見えますが、GetExternalLoginInfoAsync は null を返します。

このリンクをたどることができます https://stackoverflow.com/a/27631109/657926

于 2016-02-16T11:16:11.297 に答える
1

Tom REST API を使用して、asp.net アプリケーションで google-oauth を使用しています。正常に動作しており、接続の問題に直面していません。

私が実行している次の手順:

1.次のパラメーターを含む「WebアプリケーションのクライアントID」設定を作成したという点で、Google開発者コンソールで1つのプロジェクトを作成しました。

a) クライアント ID => Google によって自動生成されます b) メール アドレス => Google によって自動的に生成されます c) クライアント シークレット => Google によって自動的に生成されます d) リダイレクト URI => の URL を指定する必要があります認証プロセスを処理するために使用される Web ページ。このページでは、認証を行い、ユーザーの基本情報を取得できます。

my url: "http://localhost:1822/WebForm1.aspx/code"

私の使い方:

  1. 「Webpage1.aspx」と「Webpage2.aspx」を含む 1 つのサンプル プロジェクトを作成しました。

「Webpage2.aspx」スタートアップ ページを設定し、「Webpage2.aspx」でオープン認証 URL を形成し、Google ログイン ページにリダイレクトしています。

Google Open Auth URL の形成

ログイン後、アクセスコードとともに「Webpage1.aspx」にリダイレクトされます。このアクセス コードを " https://accounts.google.com/o/oauth2/token " URL に渡すことで、トークンの種類とトークンの有効期限と共にアクセス トークンを取得しています。その後、このアクセスを " https://www.googleapis.com/oauth2/v2/userinfo " URL に渡すことで、"メール、名前、性別、写真などのユーザー基本情報を取得しています...)

サンプルコード

    public class GoogleAuthorizationData
    {
        public string access_token { get; set; }
        public int expires_in { get; set; }
        public string token_type { get; set; }

    }

  public class GoogleUserInfo
    {
        public string name { get; set; }
        public string family_name { get; set; }
        public string gender { get; set; }
        public string email { get; set; }
        public string given_name { get; set; }
        public string picture { get; set; }
        public string link { get; set; }
        public string id { get; set; }

    }

  Webpage1.aspx
  ============
 protected void Page_Load(object sender, EventArgs e)
        {
            string code = Request.QueryString["code"].ToString();
            string scope = Request.QueryString["scope"].ToString();
            string url = "https://accounts.google.com/o/oauth2/token";
            string postString = "code=" + code + "&client_id=" + ConfigurationManager.AppSettings["GoogleClientID"].ToString() + "&client_secret=" + ConfigurationManager.AppSettings["GoogleSecretKey"].ToString() + "&redirect_uri=" + ConfigurationManager.AppSettings["ResponseUrl"].ToString() + "&grant_type=authorization_code";

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.ToString());
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            UTF8Encoding utfenc = new UTF8Encoding();
            byte[] bytes = utfenc.GetBytes(postString);
            Stream os = null;
            try
            {
                request.ContentLength = bytes.Length;
                os = request.GetRequestStream();
                os.Write(bytes, 0, bytes.Length);
            }
            catch
            { }

            try
            {
                HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();
                Stream responseStream = webResponse.GetResponseStream();
                StreamReader responseStreamReader = new StreamReader(responseStream);
                var result = responseStreamReader.ReadToEnd();//
                var json = new JavaScriptSerializer();

                GoogleAuthorizationData authData = json.Deserialize<GoogleAuthorizationData>(result);

                HttpWebRequest request1 = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/oauth2/v2/userinfo");
                request1.Method = "GET";
                request1.ContentLength = 0;
                request1.Headers.Add("Authorization", string.Format("{0} {1}", authData.token_type, authData.access_token));
                HttpWebResponse webResponse1 = (HttpWebResponse)request1.GetResponse();
                Stream responseStream1 = webResponse1.GetResponseStream();
                StreamReader responseStreamReader1 = new StreamReader(responseStream1);
                GoogleUserInfo userinfo = json.Deserialize<GoogleUserInfo>(responseStreamReader1.ReadToEnd());
               Response.Write(userinfo.email);

            }
            catch (Exception eX)
            {
                throw eX;
            }





        }
于 2014-05-15T17:39:29.073 に答える
1

私も同じ問題を抱えてる。Visual Studio 2013 を使用しており、Web サイトは Azure にあります。問題なく機能していたソーシャル ログインが停止し、LinkLoginCallback が loginInfo で null を受け取っていました。コードを変更したり再構築したりせずにプロジェクトを再公開したところ、loginInfo は正しいデータを受け取り、すべて正常に動作しました。意味がありませんが、そこに行きます。

于 2014-09-21T23:33:49.727 に答える
0

サードパーティの Cookie が有効になっていることを確認してください。アプリケーションにユーザーを「登録」しようとしたときにGoogleにログインしていない場合、そこにないこのCookieを探すときにログインページにリダイレクトされますが、それでも何をするかを管理することがわかりました外部プロバイダーが必要です。次に「登録」を試みるときは、プロセスの一部が完了しているため、外部 Cookie を探す必要がなくなり、2 回目は成功します。

于 2014-05-28T11:46:23.227 に答える