Skip to content

Instantly share code, notes, and snippets.

@shvydky
Last active December 11, 2015 05:58
Show Gist options
  • Save shvydky/4556009 to your computer and use it in GitHub Desktop.
Save shvydky/4556009 to your computer and use it in GitHub Desktop.
VKontakte OAuth client
using DotNetOpenAuth.AspNet.Clients;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Web;
namespace Breeze.AspNet.Security.OAuth {
public class VKontakteOAuthProvider : OAuth2Client {
string appId;
string appSecret;
public VKontakteOAuthProvider(string appId, string appSecret) : base("vkontakte") {
if (String.IsNullOrEmpty(appId)) throw new ArgumentNullException("appId");
if (String.IsNullOrEmpty(appSecret)) throw new ArgumentNullException("appSecret");
this.appId = appId;
this.appSecret = appSecret;
}
protected override Uri GetServiceLoginUrl(Uri returnUrl) {
if (returnUrl == null) throw new ArgumentNullException("returnUrl");
UriBuilder builder = new UriBuilder("https://oauth.vk.com/authorize");
var args = new Dictionary<string, string>() {
{"client_id", appId},
{"redirect_uri", NormalizeHexEncoding(returnUrl.AbsoluteUri)},
{"display", "page"},
{"response_type", "code"}
};
builder.AppendQueryArgs(args);
return builder.Uri;
}
protected override IDictionary<string, string> GetUserData(string accessToken) {
if (accessToken == null) throw new ArgumentNullException("accessToken");
var data = HttpContext.Current.Session["VKontakteOAuthProvider.Token"] as VKontakteTokenResponse;
if (data == null || data.AccessToken != accessToken)
return null;
var res = new Dictionary<string, string>();
res.Add("id", data.UserId.ToString());
UriBuilder builder = new UriBuilder("https://api.vk.com/method/users.get");
Dictionary<string, string> args = new Dictionary<string, string>();
args.Add("uids", data.UserId.ToString());
args.Add("fields", "uid,first_name,last_name,nickname,sex,bdate");
args.Add("access_token", accessToken);
builder.AppendQueryArgs(args);
using (WebClient client = new WebClient()) {
using (var stream = client.OpenRead(builder.Uri)) {
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(VKontakteDataResponse));
var info = (VKontakteDataResponse)serializer.ReadObject(stream);
if (info.Items != null && info.Items.Count() > 0) {
var item = info.Items[0];
res.AddItemIfNotEmpty("username", item.Username);
res.AddItemIfNotEmpty("name", (((item.FirstName ?? "") + " " + (item.LastName ?? "")).Trim()));
res.AddItemIfNotEmpty("birthday", item.Birthdate);
res.AddItemIfNotEmpty("gender", item.Sex);
}
}
}
return res;
}
protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) {
UriBuilder builder = new UriBuilder("https://oauth.vk.com/access_token");
Dictionary<string, string> args = new Dictionary<string, string>();
args.Add("client_id", this.appId);
args.Add("redirect_uri", NormalizeHexEncoding(returnUrl.AbsoluteUri));
args.Add("client_secret", this.appSecret);
args.Add("code", authorizationCode);
builder.AppendQueryArgs(args);
using (WebClient client = new WebClient()) {
using (var stream = client.OpenRead(builder.Uri)) {
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(VKontakteTokenResponse));
var data = (VKontakteTokenResponse)serializer.ReadObject(stream);
HttpContext.Current.Session["VKontakteOAuthProvider.Token"] = data;
return data.AccessToken;
}
}
}
private static string NormalizeHexEncoding(string url) {
char[] chArray = url.ToCharArray();
for (int i = 0; i < (chArray.Length - 2); i++) {
if (chArray[i] == '%') {
chArray[i + 1] = char.ToUpperInvariant(chArray[i + 1]);
chArray[i + 2] = char.ToUpperInvariant(chArray[i + 2]);
i += 2;
}
}
return new string(chArray);
}
}
[DataContract, EditorBrowsable(EditorBrowsableState.Never)]
internal class VKontakteTokenResponse {
[DataMember(Name = "access_token")]
public string AccessToken { get; set; }
[DataMember(Name = "user_id")]
public long UserId { get; set; }
[DataMember(Name = "expires_in")]
public long ExpiresIn { get; set; }
}
[DataContract, EditorBrowsable(EditorBrowsableState.Never)]
internal class VKontakteDataResponse {
[DataMember(Name = "response")]
public VKontakteDataItem[] Items { get; set; }
}
[DataContract, EditorBrowsable(EditorBrowsableState.Never)]
internal class VKontakteDataItem {
[DataMember(Name = "uid")]
public long UserId { get; set; }
[DataMember(Name = "sex")]
public string Sex { get; set; }
[DataMember(Name = "nickname")]
public string Username { get; set; }
[DataMember(Name = "first_name")]
public string FirstName { get; set; }
[DataMember(Name = "last_name")]
public string LastName { get; set; }
[DataMember(Name = "bdate")]
public string Birthdate { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Breeze.AspNet.Security.OAuth {
public static class Helpers {
static string[] UriRfc3986CharsToEscape = new string[] { "!", "*", "'", "(", ")" };
public static IDictionary<string, string> ParseJSON(this string str) {
return null;
}
public static void AppendQueryArgs(this UriBuilder builder, IEnumerable<KeyValuePair<string, string>> args) {
if (builder == null) throw new ArgumentNullException("builder");
if ((args != null) && (args.Count<KeyValuePair<string, string>>() > 0)) {
StringBuilder builder2 = new StringBuilder(50 + (args.Count<KeyValuePair<string, string>>() * 10));
if (!string.IsNullOrEmpty(builder.Query)) {
builder2.Append(builder.Query.Substring(1));
builder2.Append('&');
}
builder2.Append(CreateQueryString(args));
builder.Query = builder2.ToString();
}
}
public static string CreateQueryString(IEnumerable<KeyValuePair<string, string>> args) {
if (args == null) throw new ArgumentNullException("args");
if (!args.Any<KeyValuePair<string, string>>()) {
return string.Empty;
}
StringBuilder builder = new StringBuilder(args.Count<KeyValuePair<string, string>>() * 10);
foreach (KeyValuePair<string, string> pair in args) {
if (string.IsNullOrEmpty(pair.Key))
throw new ArgumentException("UnexpectedNullOrEmptyKey");
if (pair.Value == null)
throw new ArgumentException("UnexpectedNullValue");
builder.Append(EscapeUriDataStringRfc3986(pair.Key));
builder.Append('=');
builder.Append(EscapeUriDataStringRfc3986(pair.Value));
builder.Append('&');
}
builder.Length--;
return builder.ToString();
}
public static string EscapeUriDataStringRfc3986(string value) {
if (value == null) throw new ArgumentNullException("value");
StringBuilder builder = new StringBuilder(Uri.EscapeDataString(value));
for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) {
builder.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
}
return builder.ToString();
}
public static void AddItemIfNotEmpty(this IDictionary<string, string> dictionary, string key, string value) {
if (key == null) {
throw new ArgumentNullException("key");
}
if (!string.IsNullOrEmpty(value)) {
dictionary[key] = value;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment