Asp.net 如何让用户使用SoundCloud登录到我的站点
我想让用户通过SoundCloud对我的ASP.NET MVC 4项目进行身份验证。由于没有.NET SDK,我编写了一个自定义的Asp.net 如何让用户使用SoundCloud登录到我的站点,asp.net,asp.net-mvc-4,asp.net-membership,oauth-2.0,soundcloud,Asp.net,Asp.net Mvc 4,Asp.net Membership,Oauth 2.0,Soundcloud,我想让用户通过SoundCloud对我的ASP.NET MVC 4项目进行身份验证。由于没有.NET SDK,我编写了一个自定义的OAuth2Client来处理身份验证。在将客户端添加到myAuthConfig.cs之后,它适当地显示为一个登录选项。问题是,当我点击按钮登录时,它总是返回 Login Failure. Unsuccessful login with service. 甚至不要求我登录SoundCloud。有什么问题?我为GitHub实现了一个非常类似的客户端,它工作起来没有问
OAuth2Client
来处理身份验证。在将客户端添加到myAuthConfig.cs
之后,它适当地显示为一个登录选项。问题是,当我点击按钮登录时,它总是返回
Login Failure.
Unsuccessful login with service.
甚至不要求我登录SoundCloud。有什么问题?我为GitHub实现了一个非常类似的客户端,它工作起来没有问题
这是我的客户:
public class SoundCloudOAuth2Client : OAuth2Client
{
private const string ENDUSERAUTHLINK = "https://soundcloud.com/connect";
private const string TOKENLINK = "https://api.soundcloud.com/oauth2/token";
private readonly string _clientID;
private readonly string _clientSecret;
public SoundCloudOAuth2Client(string clientID, string clientSecret) : base("SoundCloud")
{
if (string.IsNullOrWhiteSpace(clientID)) {
throw new ArgumentNullException("clientID");
}
if (string.IsNullOrWhiteSpace(clientSecret)) {
throw new ArgumentNullException("clientSecret");
}
_clientID = clientID;
_clientSecret = clientSecret;
}
protected override Uri GetServiceLoginUrl(Uri returnUrl)
{
StringBuilder serviceUrl = new StringBuilder();
serviceUrl.Append(ENDUSERAUTHLINK);
serviceUrl.AppendFormat("?client_id={0}", _clientID);
serviceUrl.AppendFormat("&response_type={0}", "code");
serviceUrl.AppendFormat("&scope={0}", "non-expiring");
serviceUrl.AppendFormat("&redirect_uri={0}", System.Uri.EscapeDataString(returnUrl.ToString()));
return new Uri(serviceUrl.ToString());
}
public override void RequestAuthentication(HttpContextBase context, Uri returnUrl)
{
base.RequestAuthentication(context, returnUrl);
}
protected override IDictionary<string, string> GetUserData(string accessToken)
{
IDictionary<String, String> extraData = new Dictionary<String, String>();
var webRequest = (HttpWebRequest)WebRequest.Create("https://api.soundcloud.com/me.json?oauth_token=" + accessToken);
webRequest.Method = "GET";
string response = "";
using (HttpWebResponse webResponse = HttpWebResponse)webRequest.GetResponse())
{
using (StreamReader reader = new StreamReader(webResponse.GetResponseStream()))
{
response = reader.ReadToEnd();
}
}
var json = JObject.Parse(response);
string id = (string)json["id"];
string username = (string)json["username"];
string permalinkUrl = (string)json["permalink_url"];
extraData = new Dictionary<String, String>
{
{"SCAccessToken", accessToken},
{"username", username},
{"permalinkUrl", permalinkUrl},
{"id", id}
};
return extraData;
}
protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
{
StringBuilder postData = new StringBuilder();
postData.AppendFormat("client_id={0}", this._clientID);
postData.AppendFormat("&redirect_uri={0}", HttpUtility.UrlEncode(returnUrl.ToString()));
postData.AppendFormat("&client_secret={0}", this._clientSecret);
postData.AppendFormat("&grant_type={0}", "authorization_code");
postData.AppendFormat("&code={0}", authorizationCode);
string response = "";
string accessToken = "";
var webRequest = (HttpWebRequest)WebRequest.Create(TOKENLINK);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
using (Stream s = webRequest.GetRequestStream())
{
using (StreamWriter sw = new StreamWriter(s))
sw.Write(postData.ToString());
}
using (WebResponse webResponse = webRequest.GetResponse())
{
using (StreamReader reader = new StreamReader(webResponse.GetResponseStream()))
{
response = reader.ReadToEnd();
}
}
var json = JObject.Parse(response);
accessToken = (string)json["access_token"];
return accessToken;
}
public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl)
{
string code = context.Request.QueryString["code"];
string u = context.Request.Url.ToString();
if (string.IsNullOrEmpty(code))
{
return AuthenticationResult.Failed;
}
string accessToken = this.QueryAccessToken(returnPageUrl, code);
if (accessToken == null)
{
return AuthenticationResult.Failed;
}
IDictionary<string, string> userData = this.GetUserData(accessToken);
if (userData == null)
{
return AuthenticationResult.Failed;
}
string id = userData["id"];
string name;
if (!userData.TryGetValue("username", out name) && !userData.TryGetValue("name", out name))
{
name = id;
}
return new AuthenticationResult(
isSuccessful: true, provider: "SoundCloud", providerUserId: id, userName: name, extraData: userData);
}
}
有多个问题需要解决,从运行的第一个函数开始:
GetServiceLoginUrl(Uri returnUrl)
自动创建的returnUrl
,包含SoundCloud不喜欢的符号。您需要去掉符号,并确保SoundCloud帐户中的“用于身份验证的重定向URI”与发送的内容(querystring和all)完全匹配。以下是默认情况下作为returnURL发送的内容的示例:
https://localhost:44301/Account/ExternalLoginCallback?__provider__=SoundCloud&__sid__=blahblahyoursid
第一步是删除和\uuuu sid\uuu
值。您可以去掉sid
值并将其作为state
参数传递,以备需要。新函数如下所示:
protected override Uri GetServiceLoginUrl(Uri returnUrl)
{
StringBuilder serviceUrl = new StringBuilder();
string sid = String.Empty;
if (returnUrl.ToString().Contains("__sid__"))
{
int index = returnUrl.ToString().IndexOf("__sid__") + 8;
int len = returnUrl.ToString().Length;
sid = returnUrl.ToString().Substring(index, len - index-1);
}
string redirectUri = returnUrl.ToString().Contains('&') ?
returnUrl.ToString().Substring(0,returnUrl.ToString().IndexOf("&")) :
returnUrl.ToString();
serviceUrl.Append(ENDUSERAUTHLINK);
serviceUrl.AppendFormat("?client_id={0}", _clientID);
serviceUrl.AppendFormat("&response_type={0}", "code");
serviceUrl.AppendFormat("&scope={0}", "non-expiring");
serviceUrl.AppendFormat("&state={0}", sid);
serviceUrl.AppendFormat("&redirect_uri={0}", System.Uri.EscapeDataString(redirectUri));
return new Uri(serviceUrl.ToString());
}
这解决了部分问题。SoundlCloud中的重定向URI现在只是https://localhost:44301/Account/ExternalLoginCallback?__provider__=SoundCloud
)。但尝试验证仍将返回false
。下一个要解决的问题是AccountController.cs
,具体来说:
[AllowAnonymous]
public ActionResult ExternalLoginCallback(string returnUrl)
因为在第一行中,它试图返回:
AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
这不适用于我的自定义OAuth2Client
,因为VerifyAuthentication
采用不同的参数。通过检测是否为SoundCloud客户端,然后使用自定义VerifyAuthentication进行修复:
[AllowAnonymous]
public ActionResult ExternalLoginCallback(string returnUrl)
{
AuthenticationResult result;
var context = this.HttpContext;
string p = Tools.GetProviderNameFromQueryString(context.Request.QueryString);
if (!String.IsNullOrEmpty(p) && p.ToLower() == "soundcloud")
{
result = new SoundCloudOAuth2Client(
clientID: MyValues.SCCLIENTID,
clientSecret: MyValues.SCCLIENTSECRET).VerifyAuthentication(this.HttpContext, new Uri(String.Format("{0}/Account/ExternalLoginCallback?__provider__=SoundCloud", context.Request.Url.GetLeftPart(UriPartial.Authority).ToString())));
}
else
{
result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
}
在哪里
public static string GetProviderNameFromQueryString(NameValueCollection queryString)
{
var result = queryString["__provider__"];
///commented out stuff
return result;
}
之后,一切正常,您可以成功地进行身份验证。您可以配置
GetUserData
以获取您想要保存的任何SoundCloud数据,然后将其保存到您的UserProfile或相关表中。关键是SCAccessToken
,因为这是您将来上传到他们帐户所需的。您知道如何使用Owin进行SoundCloud身份验证吗?@gldraphael No,抱歉。我最近对Sound Cloud auth的所有使用都在node.js中。尽管我认为(希望)自从我写了这篇文章之后,会有一个关于nuget之类的软件包。
public static string GetProviderNameFromQueryString(NameValueCollection queryString)
{
var result = queryString["__provider__"];
///commented out stuff
return result;
}