Vývoj moderních aplikací na platformě Microsoft .NET

Je vyžadována podpora jazyka JavaScript

Některé stránky na tomto webu vyžadují podporu jazyka JavaScript. Váš webový prohlížeč jazyk JavaScript nepodporuje nebo jazyk JavaScript není povolen.

Chcete-li zjistit, zda webový prohlížeč podporuje jazyk JavaScript nebo jazyk JavaScript chcete povolit, přečtěte si nápovědu k vašemu webovému prohlížeči.


LiveAuthClient.cs

Download file

Toto je zdrojový kód souboru LiveAuthClient.cs

Windows Live ID (former Microsoft Account) authentication (using Live Connect REST API).

using System;
using System.IO;
using System.Net;
using System.Web;
using System.Web.UI;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

namespace WindowsLive
{
    [System.Diagnostics.DebuggerDisplay("UserID = {UserID}, FullName = {FullName}, FirstName = {FirstName}, LastName = {LastName}, Gender = {Gender}, Locale = {Locale}")]
    public sealed class LiveAuthUser
    {
        #region member varible and default property initialization
        public string UserID { get; private set; }
        public string FullName { get; private set; }
        public string FirstName { get; private set; }
        public string LastName { get; private set; }
        public string Gender { get; private set; }
        public string Locale { get; private set; }
        #endregion

        #region constructors and destructors
        internal LiveAuthUser(string userID, string fullName, string firstName, string lastName, string gender, string locale)
        {
            this.UserID = userID;
            this.FullName = fullName;
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Gender = gender;
            this.Locale = locale;
        }
        #endregion
    }

    public class LiveAuthException : Exception
    {
        #region member varible and default property initialization
        public string ErrorCode { get; private set; }
        #endregion

        #region constructors and destructors
        public LiveAuthException() { }

        public LiveAuthException(string errorCode, string message)
            : base(message)
        {
            this.ErrorCode = errorCode;
        }

        public LiveAuthException(string errorCode, string message, Exception innerException)
            : base(message, innerException)
        {
            this.ErrorCode = errorCode;
        }
        #endregion

        #region action methods
        public override string ToString()
        {
            return this.ErrorCode + ": " + base.ToString();
        }
        #endregion
    }

    public class LiveAuthClient
    {
        #region member types declaration
        private enum DisplayType
        {
            Popup,
            Touch,
        }

        private class RequestAccessTokenResults
        {
            #region member varible and default property initialization
            public string AccessToken { get; private set; }
            public DateTimeOffset Expires { get; internal set; }
            public IEnumerable<string> Scopes { get; internal set; }
            public Exception Error { get; private set; }
            #endregion

            #region constructors and destructors
            public RequestAccessTokenResults(string accessToken, DateTimeOffset expires, IEnumerable<string> scopes)
            {
                this.AccessToken = accessToken;
                this.Expires = expires;
                this.Scopes = scopes;
            }

            public RequestAccessTokenResults(Exception error)
            {
                this.Error = error;
            }
            #endregion
        }

        private class RequestUserInfoResults
        {
            #region member varible and default property initialization
            public LiveAuthUser User { get; private set; }
            public Exception Error { get; private set; }
            #endregion

            #region constructors and destructors
            public RequestUserInfoResults(LiveAuthUser user)
            {
                this.User = user;
            }

            public RequestUserInfoResults(Exception error)
            {
                this.Error = error;
            }
            #endregion
        }

        [DataContract]
        private class AuthToken
        {
            [DataMember(Name = AuthConstants.AccessToken)]
            public string AccessToken { get; private set; }

            [DataMember(Name = AuthConstants.ExpiresIn)]
            public string ExpiresIn { get; private set; }

            [DataMember(Name = AuthConstants.Scope)]
            public string Scope { get; private set; }
        }

        [DataContract]
        private class AuthUser
        {
            [DataMember(Name = AuthConstants.ID)]
            public string ID { get; set; }

            [DataMember(Name = AuthConstants.Name)]
            public string Name { get; set; }

            [DataMember(Name = AuthConstants.FirstName)]
            public string FirstName { get; set; }

            [DataMember(Name = AuthConstants.LastName)]
            public string LastName { get; set; }

            [DataMember(Name = AuthConstants.Gender)]
            public string Gender { get; set; }

            [DataMember(Name = AuthConstants.Locale)]
            public string Locale { get; set; }
        }

        [DataContract]
        private class AuthError
        {
            [DataMember(Name = AuthConstants.Error)]
            public string ErrorCode { get; private set; }

            [DataMember(Name = AuthConstants.ErrorDescription)]
            public string ErrorDescription { get; private set; }
        }

        private static class AuthConstants
        {
            #region constants
            public const string AccessToken = "access_token";
            public const string ExpiresIn = "expires_in";
            public const string Scope = "scope";
            public const string Logout = "logout";
            public const string ID = "id";
            public const string Name = "name";
            public const string FirstName = "first_name";
            public const string LastName = "last_name";
            public const string Gender = "gender";
            public const string Locale = "locale";
            public const string Error = "error";
            public const string ErrorDescription = "error_description";
            #endregion
        }
        #endregion

        #region constants
        private const string wlCookie = "wl_auth";
        private const string ConsentEndpoint = "https://oauth.live.com";
        private const string AuthorizeUrlTemplate = "{0}/authorize?client_id={1}&redirect_uri={2}&scope={3}&response_type=code&locale={4}&display={5}&state={6}";
        private const string UserInfoUrlTemplate = "https://apis.live.net/v5.0/me?access_token={0}";
        private const string AuthCodePostBodyTemplate = "client_id={0}&code={1}&redirect_uri={2}&client_secret={3}&grant_type=authorization_code";
        private const string CreateSessionState = "create_session";
        private const DisplayType Display = DisplayType.Popup;
        private static readonly string[] DefaultScopes = new[] { "wl.signin" };
        private static readonly char[] ScopeSeparators = new[] { ' ', ',' };
        #endregion

        #region member varible and default property initialization
        private readonly string ClientId;
        private readonly string ClientSecret;
        private readonly string RedirectUri;
        private IEnumerable<string> RequiredScopes;

        private bool IsInitialized;

        private string AccessToken;
        private DateTimeOffset Expires;
        private IEnumerable<string> Scopes;
        #endregion

        #region constructors and destructors
        public LiveAuthClient(string clientId, string clientSecret, string redirectUri, IEnumerable<string> requiredScopes)
        {
            if (clientId == null)
            {
                throw new ArgumentNullException("clientId");
            }
            if (clientId.Length == 0)
            {
                throw new ArgumentException("clientId is empty.", "clientId");
            }
            if (clientSecret == null)
            {
                throw new ArgumentNullException("clientSecret");
            }
            if (clientSecret.Length == 0)
            {
                throw new ArgumentException("clientSecret is empty.", "clientSecret");
            }
            if (redirectUri == null)
            {
                throw new ArgumentNullException("redirectUri");
            }
            if (redirectUri.Length == 0)
            {
                throw new ArgumentException("redirectUri is empty.", "redirectUri");
            }

            this.ClientId = clientId;
            this.ClientSecret = clientSecret;
            this.RedirectUri = redirectUri;
            this.RequiredScopes = requiredScopes ?? DefaultScopes;
        }

        public LiveAuthClient(string clientId, string clientSecret, string redirectUri) : this(clientId, clientSecret, redirectUri, null) { }
        #endregion

        #region action methods
        public LiveAuthUser GetUserInfo(Page page)
        {
            if (page == null)
            {
                throw new ArgumentNullException("page");
            }

            InitializeInternal(page);

            if (this.AccessToken != null)
            {
                var results = RequestUserInfo(this.AccessToken);
                if (results.User != null)
                {
                    return results.User;
                }
            }
            return null;
        }

        public static void SignOut()
        {
            var cookie = new HttpCookie(wlCookie);
            cookie[AuthConstants.Logout] = "1";

            HttpContext.Current.Response.Cookies.Remove(wlCookie);
            HttpContext.Current.Response.Cookies.Add(cookie);
        }

        public static void ProcessCallback(string clientId, string clientSecret, string redirectUri)
        {
            var client = new LiveAuthClient(clientId, clientSecret, redirectUri);
            client.OnAuthenticateCompleted(HttpContext.Current.Request.Url);
        }
        #endregion

        #region property getters/setters
        public string LoginUrl
        {
            get
            {
                return BuildLoginUrl(this.ClientId, this.RedirectUri, this.RequiredScopes, false, null);
            }
        }
        #endregion

        #region private member functions
        private void InitializeInternal(Page page)
        {
            if (this.IsInitialized)
            {
                return;
            }

            this.IsInitialized = true;

            HttpContext context = HttpContext.Current;
            HttpCookie cookie = context.Request.Cookies[wlCookie];

            bool isLiveSessionCreated = cookie != null;
            if (isLiveSessionCreated)
            {
                string accessToken = cookie[AuthConstants.AccessToken];
                if (!string.IsNullOrEmpty(accessToken))
                {
                    DateTimeOffset expires = DateTimeOffset.FromFileTime(Int64.Parse(cookie[AuthConstants.ExpiresIn]));

                    //Check Expiration
                    if (expires > DateTimeOffset.UtcNow.Add(new TimeSpan(0, 0, 60)))
                    {
                        this.AccessToken = accessToken;
                        this.Scopes = ParseScopeString(cookie[AuthConstants.Scope]);
                        this.Expires = expires;
                        return;
                    }
                    isLiveSessionCreated = false;
                }

                if (cookie[AuthConstants.Logout] == "1")    //Run logout script
                {
                    page.ClientScript.RegisterClientScriptBlock(page.GetType(), "logout", "logoutWindowsLive();", true);
                    SetLiveAuthCookie();    //Create empty cookie
                    return;
                }
            }

            if (!OnAuthenticateCompleted(HttpContext.Current.Request.Url) && !isLiveSessionCreated)
            {
                //Silent authentication
                context.Response.Redirect(BuildLoginUrl(this.ClientId, this.RedirectUri, this.RequiredScopes, true, CreateSessionState));
            }
        }

        private bool OnAuthenticateCompleted(Uri responseUri)
        {
            var dictionary = ParseQueryString(responseUri.Query);

            string code;
            if (dictionary.TryGetValue("code", out code) && !string.IsNullOrEmpty(code))
            {
                var results = RequestAccessToken(code, this.ClientId, this.ClientSecret, this.RedirectUri);
                if (results.Error == null)
                {
                    this.AccessToken = results.AccessToken;
                    this.Expires = results.Expires;
                    this.Scopes = results.Scopes;

                    SetLiveAuthCookie();
                    return true;
                }
            }

            string state;
            if (dictionary.TryGetValue("state", out state) && state == CreateSessionState)
            {
                SetLiveAuthCookie();    //Create empty cookie
                return true;
            }
            return false;
        }

        private void SetLiveAuthCookie()
        {
            var cookie = new HttpCookie(wlCookie);
            if (this.AccessToken != null)
            {
                cookie[AuthConstants.AccessToken] = HttpUtility.UrlEncode(this.AccessToken);
                cookie[AuthConstants.Scope] = HttpUtility.UrlPathEncode(BuildScopeString(this.Scopes));
                cookie[AuthConstants.ExpiresIn] = this.Expires.ToFileTime().ToString();
            }

            HttpContext.Current.Response.Cookies.Remove(wlCookie);
            HttpContext.Current.Response.Cookies.Add(cookie);
        }

        private static RequestAccessTokenResults RequestAccessToken(string code, string clientId, string clientSecret, string redirectUri)
        {
            Uri url = new Uri(ConsentEndpoint + "/token");
            string body = string.Format(AuthCodePostBodyTemplate, HttpUtility.UrlEncode(clientId), code, redirectUri, HttpUtility.UrlEncode(clientSecret));

            var request = WebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";

            try
            {
                using (var writer = new StreamWriter(request.GetRequestStream()))
                {
                    writer.Write(body);
                }

                var response = request.GetResponse();
                if (response != null)
                {
                    Stream responseStream = response.GetResponseStream();
                    if (responseStream != null)
                    {
                        try
                        {
                            var serializer = new DataContractJsonSerializer(typeof(AuthToken));
                            var token = (AuthToken)serializer.ReadObject(responseStream);
                            if (token != null)
                            {
                                return new RequestAccessTokenResults(token.AccessToken, DateTimeOffset.UtcNow.AddSeconds((double)Int64.Parse(token.ExpiresIn)), ParseScopeString(token.Scope));
                            }
                        }
                        catch (FormatException ex)
                        {
                            return new RequestAccessTokenResults(ex);
                        }
                    }
                }
            }
            catch (WebException e)
            {
                var response = e.Response;
                if (response != null)
                {
                    Stream responseStream = response.GetResponseStream();
                    if (responseStream != null)
                    {
                        try
                        {
                            var serializer = new DataContractJsonSerializer(typeof(AuthError));
                            var error = (AuthError)serializer.ReadObject(response.GetResponseStream());
                            if (error != null)
                            {
                                return new RequestAccessTokenResults(new LiveAuthException(error.ErrorCode, error.ErrorDescription));
                            }
                        }
                        catch (FormatException ex)
                        {
                            return new RequestAccessTokenResults(ex);
                        }
                    }
                }
            }
            catch (IOException)
            {
                //Ignore exception
            }

            return new RequestAccessTokenResults(new LiveAuthException("client_error", "A connection to the server could not be established."));
        }

        private static RequestUserInfoResults RequestUserInfo(string accessToken)
        {
            Uri url = new Uri(string.Format(UserInfoUrlTemplate, accessToken));
            var request = WebRequest.Create(url);

            try
            {
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                if (response != null)
                {
                    Stream responseStream = response.GetResponseStream();
                    if (responseStream != null)
                    {
                        try
                        {
                            var serializer = new DataContractJsonSerializer(typeof(AuthUser));
                            var user = (AuthUser)serializer.ReadObject(responseStream);
                            if (user != null)
                            {
                                return new RequestUserInfoResults(new LiveAuthUser(user.ID, user.Name, user.FirstName, user.LastName, user.Gender, user.Locale));
                            }
                        }
                        catch (FormatException ex)
                        {
                            return new RequestUserInfoResults(ex);
                        }
                    }
                }
            }
            catch (WebException e)
            {
                var response = e.Response;
                if (response != null)
                {
                    Stream responseStream = response.GetResponseStream();
                    if (responseStream != null)
                    {
                        try
                        {
                            var serializer = new DataContractJsonSerializer(typeof(AuthError));
                            var error = (AuthError)serializer.ReadObject(response.GetResponseStream());
                            if (error != null)
                            {
                                return new RequestUserInfoResults(new LiveAuthException(error.ErrorCode, error.ErrorDescription));
                            }
                        }
                        catch (FormatException ex)
                        {
                            return new RequestUserInfoResults(ex);
                        }
                    }
                }
            }
            catch (IOException)
            {
                //Ignore exception
            }

            return new RequestUserInfoResults(new LiveAuthException("client_error", "A connection to the server could not be established."));
        }

        private static string BuildLoginUrl(string clientId, string redirectUri, IEnumerable<string> scopes, bool silent, string state)
        {
            return string.Format(AuthorizeUrlTemplate,
                ConsentEndpoint,
                HttpUtility.UrlEncode(clientId),
                HttpUtility.UrlEncode(redirectUri),
                HttpUtility.UrlEncode(BuildScopeString(scopes)),
                HttpUtility.UrlEncode(System.Globalization.CultureInfo.CurrentUICulture.ToString()),
                silent ? "none" : HttpUtility.UrlEncode(Display.ToString().ToLowerInvariant()),
                state);
        }

        private static string BuildScopeString(IEnumerable<string> scopes)
        {
            var sb = new System.Text.StringBuilder();
            if (scopes != null)
            {
                foreach (string str in scopes)
                {
                    sb.Append(str).Append(ScopeSeparators[0]);
                }
            }
            return sb.ToString().TrimEnd(ScopeSeparators);
        }

        private static IEnumerable<string> ParseScopeString(string scopesString)
        {
            return new List<string>(scopesString.Split(ScopeSeparators, StringSplitOptions.RemoveEmptyEntries));
        }

        private static IDictionary<string, string> ParseQueryString(string query)
        {
            var dictionary = new Dictionary<string, string>();
            if (!string.IsNullOrEmpty(query))
            {
                query = query.TrimStart(new char[] { '?', '#' });
                if (string.IsNullOrEmpty(query))
                {
                    return dictionary;
                }
                foreach (string str in query.Split(new char[] { '&' }))
                {
                    string[] strArray2 = str.Split(new char[] { '=' });
                    if (strArray2.Length == 2)
                    {
                        dictionary.Add(strArray2[0], strArray2[1]);
                    }
                }
            }
            return dictionary;
        }
        #endregion
    }
}