我们希望制作一个将身份验证外包给谷歌的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")
);
}
}
但是我得到一个错误beacuse wa没有在QueryString中指定,调试样本和生成的模板我看到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 /'。”
任何提示? 谢谢!
答案 0 :(得分: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);
}