1

認証をグーグルにアウトソーシングするSTSを作りたい。

https://developers.google.com/accounts/docs/OAuth2Login?hl=es-ESに記載されている手順に従って、vs2010のstsWebサイトテンプレートによって生成されたLogin.aspxに次のコードがあります。

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.QueryString["code"] != null)
    {
        //I'm coming from google, already authenticated
        FormsAuthentication.SetAuthCookie(GetUserName(Request.QueryString["code"]), false);
        Response.Redirect("default.aspx");
    }
    else
    {
        //I want to authenticate
        Response.Redirect(
            "https://accounts.google.com/o/oauth2/auth?" +
            "response_type=code&" +
            "client_id=988046895016.apps.googleusercontent.com&" +
            "redirect_uri=" + HttpUtility.UrlEncode("https://localhost/GmailSTS/login.aspx") + "&" +
            "scope=" + HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.email")
            );
    }
}

しかし、クエリ文字列でwaが指定されていないため、エラーが発生します。サンプルと生成されたテンプレートをデバッグすると、wa、wtrealm、wctx、wctが必要なパラメーターであることがわかりました。そのため、stateパラメーターを使用して、ラウンドトリップして元に戻しました。

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.QueryString["code"] != null)
    {
        //I'm coming from google, already authenticated
        FormsAuthentication.SetAuthCookie("johannsw", false);
        String lQueryStrings = HttpUtility.UrlDecode(Request.QueryString["state"]);
        lQueryStrings.Replace('?', '&');
        Response.Redirect("default.aspx" + "?" + lQueryStrings);

    }
    else
    {
        //I want to authenticate
        String lState = String.Empty;
        foreach (var key in Request.QueryString.AllKeys)
        {
            if (String.Equals("wa", key) ||
                String.Equals("wtrealm", key) ||
                String.Equals("wctx", key) ||
                String.Equals("wct", key))
                lState += key + "=" + Request.QueryString[key] + "&";
        }
        lState = lState.Remove(lState.Length - 1);

        Response.Redirect(
            "https://accounts.google.com/o/oauth2/auth?" +
            "response_type=code&" +
            "client_id=988046895016.apps.googleusercontent.com&" +
            "redirect_uri=" + HttpUtility.UrlEncode("https://localhost/GmailSTS/login.aspx") + "&" +
            "scope=" + HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.email") + "&" +
            "state=" + HttpUtility.UrlEncode(lState)
            );
    }
}

しかし、「パス'/WebSite1/'へのアクセスに使用されるHTTP動詞POSTは許可されていません」というエラーが表示されます。

ヒントはありますか?ありがとう!

4

1 に答える 1

1

さてようやくできました。これが他の誰かを助ける場合に備えて私がそれを解決した方法です:

Login.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.QueryString["code"] != null && Request.QueryString["error"] != "access_denied")
    { 
        // If I got code and no error then 
        // ask for access_code so I can get user email

        //Here I ask for the access_code.
        WebRequest requestLogIn = null;
        Stream stream = null;
        WebResponse response = null;
        StreamReader reader = null;

        string sendData = "code=" + Request.QueryString["code"] + "&";
        sendData += "client_id=" + ObtenerClientID() + "&";
        sendData += "client_secret=" + ObtenerClientSecret() + "&";
        sendData += "redirect_uri=" + System.Configuration.ConfigurationManager.AppSettings["urlLogin"] + "&"; //TODO: ver si es necesario
        sendData += "grant_type=authorization_code";

        requestLogIn = WebRequest.Create("https://accounts.google.com/o/oauth2/token");

        requestLogIn.Method = "POST";
        requestLogIn.ContentType = "application/x-www-form-urlencoded";

        byte[] arrayToSend = Encoding.UTF8.GetBytes(sendData);
        requestLogIn.ContentLength = arrayToSend.Length;

        stream = requestLogIn.GetRequestStream();
        stream.Write(arrayToSend, 0, arrayToSend.Length);
        stream.Close();

        response = requestLogIn.GetResponse();

        if (((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
        {
            stream = response.GetResponseStream();
            reader = new StreamReader(stream);
            string responseValue = reader.ReadToEnd();
            reader.Close();

            var lJSONResponse = new JavaScriptSerializer().Deserialize<JSONResponseToken>(responseValue);

            //Now that I have the access_code ask for the user email so I can match him in my base and load claims.

            WebRequest myRequest = WebRequest.Create("https://www.googleapis.com/oauth2/v2/userinfo");
            myRequest.Method = "GET";

            myRequest.Headers.Add("Authorization", "Bearer " + lJSONResponse.Access_Token);

            response = myRequest.GetResponse();
            if (((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
            {
                stream = response.GetResponseStream();
                reader = new StreamReader(stream);
                responseValue = reader.ReadToEnd();

                var lUserMail = new JavaScriptSerializer().Deserialize<JSONResponseUserMail>(responseValue);

                // User is authenticated
                FormsAuthentication.SetAuthCookie(lUserMail.Email, false);

                // default.aspx will load claims
                Response.Redirect("default.aspx?" + Request.QueryString.ToString());
            }
        }


    }
    else
    {
        //redirect to google for login.

        //Save original url in a cookie for later use.
        Guid lGuid = Guid.NewGuid();
        CreateContextCookie(lGuid.ToString(), this.Request.Url.AbsoluteUri);

        Response.Redirect(
            "https://accounts.google.com/o/oauth2/auth?" +
            "response_type=code&" +
            "client_id=" + ObtenerClientID() + "&" +
            //I want to return here again
            "redirect_uri=" + HttpUtility.UrlEncode(System.Configuration.ConfigurationManager.AppSettings["urlLogin"]) + "&" + 
            //Add scope so I can get user mail.
            "scope=" + HttpUtility.UrlEncode("https://www.googleapis.com/auth/userinfo.email") + "&" +
            //Reference to the cookie so I can get the original url again
            "state=" + HttpUtility.UrlEncode(lGuid.ToString())
            );
    }
}

Default.aspx.cs:

protected void Page_PreRender(object sender、EventArgs e){

    String lCode = Request.QueryString["code"];
    String lSTate = Request.QueryString["state"];
    var ctxCookie = this.Request.Cookies[lSTate];

    var requestMessage = (SignInRequestMessage)WSFederationMessage.CreateFromUri(new Uri(ctxCookie.Value));
    //Erase cookie
    var contextCookie = new HttpCookie(lSTate)
    {
        Expires = DateTime.UtcNow.AddDays(-1)
    };

    //process login request
    SecurityTokenService sts =
        new CustomSecurityTokenService(CustomSecurityTokenServiceConfiguration.Current);
    SignInResponseMessage responseMessage =
        FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(requestMessage, this.User, sts);
    FederatedPassiveSecurityTokenServiceOperations.ProcessSignInResponse(responseMessage, this.Response);

    this.Response.Cookies.Add(contextCookie);
}
于 2012-06-05T14:24:28.673 に答える