using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
namespace VK
{
///
/// Авторицаия ВКонтакте
///
class VKAuth
{
#region Fields
//неверный ответ от сервера
public delegate void ServerErrorCallback();
public event ServerErrorCallback ServerError;
//успешный logout
public delegate void LogoutCompletedCallback();
public event LogoutCompletedCallback LogoutCompleted;
//успешный login
public delegate void LoginCompletedCallback(string token, string userId);
public event LoginCompletedCallback LoginCompleted;
//тип текущего действия
public enum VKAuthActionType { Login, Logout }
private VKAuthActionType _actionType;
//контейнер для WebBrowser
private Grid _gridContainer;
//маркер загрузки
public bool IsLoading = false;
//стандартный редирект при логине
private const string RedirectUrl = "https://oauth.vk.com/blank.html";
private readonly WebBrowser _webBrowser;
#endregion
#region Constructor
public VKAuth()
{
_webBrowser = new WebBrowser { IsScriptEnabled = true };
_webBrowser.NavigationFailed += WebBrowserNavigationFailed;
}
#endregion
#region NavigationFailed
private void WebBrowserNavigationFailed(object sender, NavigationFailedEventArgs e)
{
IsLoading = false;
if (_actionType == VKAuthActionType.Login)
{
_webBrowser.Visibility = System.Windows.Visibility.Collapsed;
if (ServerError != null)
ServerError();
}
else
{
if (LogoutCompleted != null)
LogoutCompleted();
}
}
#endregion
#region Login
public void LoginAsync(Page page, string appId, string scope)
{
if (IsLoading) return;
IsLoading = true;
_actionType = VKAuthActionType.Login;
_gridContainer = page.Content as Grid;
var url =
String.Format("https://api.vk.com/oauth/authorize?client_id={0}&scope={1}&display=touch&response_type=token", appId, scope);
var loginUrl = new Uri(url, UriKind.Absolute);
_webBrowser.Navigated += WebBrowserNavigated;
_webBrowser.Navigate(loginUrl);
}
private void WebBrowserNavigated(object sender, NavigationEventArgs e)
{
var result = ParseNavigatedUrl(e.Uri.ToString());
if (result.Status != AuthorzationStatus.Unknown)
{
_webBrowser.Visibility = System.Windows.Visibility.Collapsed;
if (result.Status == AuthorzationStatus.Success)
{
var token = result.Context.AccessToken;
var userId = result.Context.CurrentUserId;
if (LoginCompleted != null)
LoginCompleted(token, userId);
}
else
{
if (ServerError != null)
ServerError();
}
IsLoading = false;
}
else
{
if (!_gridContainer.Children.Contains(_webBrowser))
{
Grid.SetColumnSpan(_webBrowser, int.MaxValue);
Grid.SetRowSpan(_webBrowser, int.MaxValue);
_gridContainer.Children.Add(_webBrowser);
}
}
}
public void LoginCancel()
{
if (_actionType == VKAuthActionType.Logout) return;
IsLoading = false;
_webBrowser.Visibility = System.Windows.Visibility.Collapsed;
}
#endregion
#region Logout
public void LogoutAsync()
{
if (IsLoading) return;
IsLoading = true;
_actionType = VKAuthActionType.Logout;
_webBrowser.LoadCompleted += WebBrowserLogouted;
_webBrowser.Navigate(new Uri(@"https://m.vk.com/"));
}
private void WebBrowserLogouted(object sender, NavigationEventArgs e)
{
var page = _webBrowser.SaveToString();
if (page.Contains("https://login.vk.com/?act=logout_mobile"))
{
var hash = page.Substring(page.IndexOf(@"https://login.vk.com/?act=logout_mobile", StringComparison.Ordinal));
hash = hash.Substring(hash.IndexOf("hash=", StringComparison.Ordinal));
hash = hash.Substring(5, hash.IndexOf(@"&", StringComparison.Ordinal) - 5);
var logout = @"https://login.vk.com/?act=logout_mobile&hash=" + hash + "&from_host=m.vk.com&from_protocol=http";
_webBrowser.LoadCompleted -= WebBrowserLogouted;
_webBrowser.Navigated += WebBrowserLogoutNavigated;
_webBrowser.Navigate(new Uri(logout));
}
else
{
IsLoading = false;
LogoutCompleted();
}
}
private void WebBrowserLogoutNavigated(object sender, NavigationEventArgs e)
{
IsLoading = false;
LogoutCompleted();
}
#endregion
#region Helpers
private static AuthorizationResult ParseNavigatedUrl(string url)
{
if (url.StartsWith(RedirectUrl) && url.Length > RedirectUrl.Length)
{
var tokenData = GetToken(url);
var tokenArray = GetTokenArray(tokenData);
var authorizationResult = GetAuthResult(tokenArray);
return authorizationResult;
}
return new AuthorizationResult { Status = AuthorzationStatus.Unknown };
}
private static string GetToken(string url)
{
return url.Substring(RedirectUrl.Length + 1);
}
private static Dictionary GetTokenArray(string tokenData)
{
var result = new Dictionary();
var keyValuePairs = tokenData.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
var splitedKeyValuePairs = keyValuePairs.Select(i => i.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries)).ToList();
splitedKeyValuePairs.ForEach(j => result.Add(j[0], j[1]));
return result;
}
private static AuthorizationResult GetAuthResult(Dictionary tokenArray)
{
var authorizationResult = new AuthorizationResult();
if (tokenArray.ContainsKey("error"))
{
authorizationResult.Status = AuthorzationStatus.Error;
authorizationResult.Description = tokenArray["error"];
}
else
{
authorizationResult.Status = AuthorzationStatus.Success;
authorizationResult.Description = "success";
authorizationResult.Context = new AuthorizationContext
{
AccessToken = tokenArray["access_token"],
CurrentUserId = tokenArray["user_id"],
};
}
return authorizationResult;
}
public enum AuthorzationStatus
{
Unknown,
Success,
Error
}
public class AuthorizationContext
{
public string CurrentUserId { get; set; }
public string AccessToken { get; set; }
public string ApplicationId { get; set; }
}
public class AuthorizationResult
{
public AuthorzationStatus Status { get; set; }
public AuthorizationContext Context { get; set; }
public string Description { get; set; }
}
#endregion
}
}