1

我们想制作一个将身份验证外包给谷歌的 STS。

按照https://developers.google.com/accounts/docs/OAuth2Login?hl=es-ES中所述的步骤,我们在 vs2010 中的 sts 网站模板生成的 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")
            );
    }
}

但是我收到一个错误,因为 QueryString 中没有指定 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)
            );
    }
}

但现在我收到一条错误消息,提示“不允许使用 HTTP 动词 POST 访问路径 '/WebSite1/'。”

有什么提示吗?谢谢!

4

1 回答 1

1

好吧,我终于成功了。这是我解决它的方法,以防万一它帮助别人:

登录.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())
            );
    }
}

默认.aspx.cs:

protected void Page_PreRender(对象发送者,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 回答