程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> SimpleSSO:使用Microsoft.Owin.Security.OAuth搭建OAuth2.0授權服務端,

SimpleSSO:使用Microsoft.Owin.Security.OAuth搭建OAuth2.0授權服務端,

編輯:關於.NET

SimpleSSO:使用Microsoft.Owin.Security.OAuth搭建OAuth2.0授權服務端,


目錄

  • 前言

  • OAuth2.0簡介

  • 授權模式 (SimpleSSO示例) 

  • 使用Microsoft.Owin.Security.SimpleSSO模擬OpenID認證

  • 通過authorization code授權模式申請令牌

  • 通過implicit授權模式申請令牌

  • 通過password模式申請令牌

  • 通過client credentials模式申請令牌

  • 後話

前言

  之前有分享這個項目源碼及簡介,不過因為文字講解太少,被和諧了。我重新總結下:

  

 

   源碼:https://github.com/zhoufeihong/SimpleSSO

   OAuth 2.0協議:http://www.rfcreader.com/#rfc6749

-------------------------------------------分割線

  

  記得那個酷熱的夏天,面試官翹著二郎腿問:“知道單點登錄不?”,我毫不遲疑答到:“不就是限制用戶只能在一個地方登錄嗎!”。面試完回家,查資料,也是似懂非懂,COOKIE、跨域、令牌、主站都是些啥玩意!其實我就是個VS都沒摸過幾次的畢業生,單點登錄這種玩意是不是太高級了。

  這次就是寫個項目練練手(這兩年手生了太多),想到當初在網上找了半天,關於單點登錄、OAuth 2.0也沒找到個完整的實例(概念、理論倒是比較多),就寫了這個項目。分享出來,希望可以給那些對單點登錄、OAuth 2.0實現比較困惑的C#開發人員一些幫助。同時項目裡面有對於Autofac、AutoMapper、EF等等技術實踐方式(當然復制了很多代碼,我會盡量把源項目的License放上),希望在這些技術上也可以給你一些參考,項目可以直接運行(用戶名:admin密碼:123)。

  昨天的文章因為文字講解太少了,被和諧了。不得不佩服博客園管理人員的專業水平,是你們如此細致的工作造就了博客園這麼多優秀的文章,也造就了博客園的今天(拍個馬屁)。其實我就想貼幾張圖,你們看到效果後,自己去看代碼、敲代碼,這樣子會比較好些(其實我就是表達能力不好,怕詞不達意)。

  廢話不多說了,這篇文章我簡單介紹下:

  SimpleSSO授權第三方應用系統獲取用戶信息(OpenID認證)(類似於我們在新浪上點擊QQ快捷登錄,采用的授權碼模式(authorization code))

  SimpleSSO授權基於浏覽器應用系統獲取用戶信息(類似於我們通過微信浏覽器點開第三方應用,采用的簡化模式(implicit))

  第三方系統使用用戶名密碼申請獲取用戶令牌,然後用令牌獲取用戶信息(采用的密碼模式(password))

  第三方系統申請自己的訪問令牌(類似於微信公眾號用申請令牌訪問自己公眾號信息(采用的客戶端模式client credentials))

  第三方系統刷新用戶(本身)令牌(refreshtoken)

 

OAuth2.0簡介

   OAuth2.0(開放授權)是一個開放標准,允許用戶讓第三方應用訪問該用戶在某一網站上存儲的私密的資源,而無需將用戶名和密碼提供給第三方應用。具體你可以去百度(oauth2.0 阮一峰),文章關於oauth2.0理論的講解非常到位,網上的理論也非常多,之前沒有基礎的可以先去腦補下。 

      具體場景:QQ用戶在XX網站分享文章到QQ空間

      剖析:

  

 

授權模式 (SimpleSSO授權示例)

前言:

    關於授權模式如果不太清楚的建議:去百度(oauth2.0 阮一峰),文章關於對於授權模式的講解非常到位。Owin.OAuth的基礎,可以看看dudu寫的在ASP.NET中基於Owin OAuth使用Client Credentials Grant授權發放Token,一篇一篇看下去。

    本節主要演示SimpleSSOTest站點通過各種授權模式到SimpleSSO站點申請令牌。如圖:

      

    其中SimpleSSO站點為:http://localhost:8550,SimpleTest站點為:http://localhost:6111,後續會用到

    SimpleSSO關於OAuthAuthorizationServerOptions的配置:

  builder.Register(c => new OAuthAuthorizationServerOptions
            {
                //授權終結點 /Token
                TokenEndpointPath = new PathString(EndPointConfig.TokenEndpointPath),
                Provider = new SimpleSSOOAuthProvider(),
                // Authorize授權終結點 /GrantCode/Authorize
                AuthorizeEndpointPath = new PathString(EndPointConfig.AuthorizeEndpointPath),
                //RefreshToken令牌創建、接收
                RefreshTokenProvider = new SimpleAuthenticationTokenProvider()
                {
                    //令牌類型
                    TokenType = "RefreshToken",
                    //刷新AccessToken時RefreshToken不需要重新生成
                    TokenKeepingPredicate = data => data.GrantType == GrantTypes.RefreshToken,
                    //過期時間
                    ExpireTimeSpan = TimeSpan.FromDays(60)
                },
                // AccessToken令牌創建、接收
                AccessTokenProvider = new SimpleAuthenticationTokenProvider()
                {
                    //令牌類型
                    TokenType = "AccessToken",
                    //過期時間
                    ExpireTimeSpan = TimeSpan.FromHours(2)
                },
                // AuthorizationCode令牌創建、接收
                AuthorizationCodeProvider = new SimpleAuthenticationTokenProvider()
                {
                    //令牌類型
                    TokenType = "AuthorizationCode",
                    //過期時間
                    ExpireTimeSpan = TimeSpan.FromMinutes(15),
                    //接收令牌,同時移除令牌
                    RemoveWhenReceive = true
                },
                //在生產模式下設 AllowInsecureHttp = false
#if DEBUG
                AllowInsecureHttp = true
#endif
            }).As<OAuthAuthorizationServerOptions>().SingleInstance();
View Code

    其中兩個關於OAuth授權的實現類:

    令牌生成接收:SimpleAuthenticationTokenProvider

    授權總線:SimpleSSOOAuthProvider

 

授權示例:

1、使用Microsoft.Owin.Security.SimpleSSO模擬OpenID認證(authorization code模式)

1.1、Demo展示:

 

今天新加了Microsoft.Owin.Security.SimpleSSO組件(感興趣的可以看下Katana項目),主要方便第三方集成SimpleSSO登錄。

SimpleTest集成登錄需要完成如下代碼配置:

    public partial class Startup
    {
        // 有關配置身份驗證的詳細信息,請訪問 http://go.microsoft.com/fwlink/?LinkId=301864
        public void ConfigureAuth(IAppBuilder app)
        {
            // 並使用 Cookie 來臨時存儲有關使用第三方登錄提供程序登錄的用戶的信息
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
            //simplesso登錄集成配置
        var simpleSSOOption = new SimpleSSOAccountAuthenticationOptions
            {
                //客戶端ID
                ClientId = "3",
                //客戶端秘鑰
                ClientSecret = "123",
                //登錄回調地址
                CallbackPath = new PathString("/login/signin-simplesso"),
                //SimpleSSO Token授權地址
                TokenEndpoint = "http://localhost:8550/token",
                //SimpleSSO authorization code授權地址
                AuthorizationEndpoint = "http://localhost:8550/GrantCode/Authorize",
                //使用令牌到SimpleSSO獲取用戶信息地址
                UserInformationEndpoint = "http://localhost:8550/TicketUser/TicketMessage"
            };
            simpleSSOOption.Scope.Add("user-base");
            app.UseSimpleSSOAccountAuthentication(simpleSSOOption);
            app.UseFacebookAuthentication(
                appId: "",
                appSecret: "");
        }
    }
View Code

 1.2、Demo請求流程(流程圖工具過期了,只能用文字了,省略了很多細節):

1)用戶點擊“使用Microsoft.Owin.Security.SimpleSSO模擬OpenID認證”下進入按鈕,將跳轉到http://localhost:6111/login/authsimplesso

2)authsimplesso接收用戶請求

  1>如果用戶已經使用ExternalCookie在登錄,注銷ExternalCookie信息,獲取返回用戶信息。

  2>當用戶未登錄,則將http返回狀態改為401,並且創建authenticationType為SimpleSSOAuthentication身份驗證,SimpleSSOAccountAuthenticationHandler將用戶重定向到http://localhost:8550/GrantCode/Authorize?client_id={0}&scope={1}&response_type=code&redirect_uri={2}&state={3}。

SimpleSSOAccountAuthenticationHandler重定向代碼:

protected override Task ApplyResponseChallengeAsync()
        {
            if (Response.StatusCode != 401)
            {
                return Task.FromResult<object>(null);
            }
            AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
            if (challenge != null)
            {
                string baseUri = Request.Scheme + Uri.SchemeDelimiter + Request.Host + Request.PathBase;
                string currentUri = baseUri + Request.Path + Request.QueryString;
                string redirectUri = baseUri + Options.CallbackPath;
                AuthenticationProperties extra = challenge.Properties;
                if (string.IsNullOrEmpty(extra.RedirectUri))
                {
                    extra.RedirectUri = currentUri;
                }
                // OAuth2 10.12 CSRF
                GenerateCorrelationId(extra);
                // OAuth2 3.3 space separated                
        string scope = string.Join(" ", Options.Scope);
                // LiveID requires a scope string, so if the user didn't set one we go for the least possible.
        if (string.IsNullOrWhiteSpace(scope))
                {
                    scope = "user-base";
                }
                string state = Options.StateDataFormat.Protect(extra);
                string authorizationEndpoint =
                    Options.AuthorizationEndpoint +
        "?client_id=" + Uri.EscapeDataString(Options.ClientId) +
        "&scope=" + Uri.EscapeDataString(scope) +
        "&response_type=code" +
        "&redirect_uri=" + Uri.EscapeDataString(redirectUri) +
        "&state=" + Uri.EscapeDataString(state);
                var redirectContext = new SimpleSSOAccountApplyRedirectContext(
                    Context, Options,
                    extra, authorizationEndpoint);
                Options.Provider.ApplyRedirect(redirectContext);
            }
            return Task.FromResult<object>(null);
        }
View Code

3)GrantCode/Authorize接收用戶請求

  1>如果為可信應用則不需要用戶同意,直接生成code讓用戶跳轉到http://localhost:6111/login/signin-simplesso?code={0}&state={1}

  2>如果不是可信應用則跳轉到http://localhost:8550/OAuth/Grant用戶授權頁面,用戶點擊授權時跳轉到

4)http://localhost:6111/login/signin-simplesso?code={0}&state={1}請求處理,由SimpleSSOAccountAuthenticationHandler類處理

    SimpleSSOAccountAuthenticationHandler代碼:

 internal class SimpleSSOAccountAuthenticationHandler : AuthenticationHandler<SimpleSSOAccountAuthenticationOptions>
    {
        private readonly ILogger _logger;
        private readonly HttpClient _httpClient;
        public SimpleSSOAccountAuthenticationHandler(HttpClient httpClient, ILogger logger)
        {
            _httpClient = httpClient;
            _logger = logger;
        }
        public override async Task<bool> InvokeAsync()
        {
            if (Options.CallbackPath.HasValue && Options.CallbackPath == Request.Path)
            {
                return await InvokeReturnPathAsync();
            }
            return false;
        }
        protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
        {
            AuthenticationProperties properties = null;
            try
            {
                string code = null;
                string state = null;
                IReadableStringCollection query = Request.Query;
                IList<string> values = query.GetValues("code");
                if (values != null && values.Count == 1)
                {
                    code = values[0];
                }
                values = query.GetValues("state");
                if (values != null && values.Count == 1)
                {
                    state = values[0];
                }
                properties = Options.StateDataFormat.Unprotect(state);
                if (properties == null)
                {
                    return null;
                }
                // OAuth2 10.12 CSRF
        if (!ValidateCorrelationId(properties, _logger))
                {
                    return new AuthenticationTicket(null, properties);
                }
                var tokenRequestParameters = new List<KeyValuePair<string, string>>()
                {
                    new KeyValuePair<string, string>("client_id", Options.ClientId),
                    new KeyValuePair<string, string>("redirect_uri", GenerateRedirectUri()),
                    new KeyValuePair<string, string>("client_secret", Options.ClientSecret),
                    new KeyValuePair<string, string>("code", code),
                    new KeyValuePair<string, string>("grant_type", "authorization_code"),
                };
                var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
                HttpResponseMessage response = await _httpClient.PostAsync(Options.TokenEndpoint, requestContent, Request.CallCancelled);
                response.EnsureSuccessStatusCode();
                string oauthTokenResponse = await response.Content.ReadAsStringAsync();
                JObject oauth2Token = JObject.Parse(oauthTokenResponse);
                var accessToken = oauth2Token["access_token"].Value<string>();
                // Refresh token is only available when wl.offline_access is request.
                // Otherwise, it is null.
        var refreshToken = oauth2Token.Value<string>("refresh_token");
                var expire = oauth2Token.Value<string>("expires_in");
                if (string.IsNullOrWhiteSpace(accessToken))
                {
                    _logger.WriteWarning("Access token was not found");
                    return new AuthenticationTicket(null, properties);
                }
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                HttpResponseMessage graphResponse = await _httpClient.GetAsync(
                    Options.UserInformationEndpoint);
                graphResponse.EnsureSuccessStatusCode();
                string accountString = await graphResponse.Content.ReadAsStringAsync();
                JObject accountInformation = JObject.Parse(accountString);
                var context = new SimpleSSOAccountAuthenticatedContext(Context, accountInformation, accessToken,
                    refreshToken, expire);
                context.Identity = new ClaimsIdentity(
                    new[]
                    {
                        new Claim(ClaimTypes.NameIdentifier, context.Id, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType),
                        new Claim(ClaimTypes.Name, context.Name, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType),
                        new Claim("urn:simplesso:id", context.Id, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType),
                        new Claim("urn:simplesso:name", context.Name, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType)
                    },
                    Options.AuthenticationType,
                    ClaimsIdentity.DefaultNameClaimType,
                    ClaimsIdentity.DefaultRoleClaimType);
                if (!string.IsNullOrWhiteSpace(context.Email))
                {
                    context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType));
                }
                await Options.Provider.Authenticated(context);
                context.Properties = properties;
                return new AuthenticationTicket(context.Identity, context.Properties);
            }
            catch (Exception ex)
            {
                _logger.WriteError("Authentication failed", ex);
                return new AuthenticationTicket(null, properties);
            }
        }
        protected override Task ApplyResponseChallengeAsync()
        {
            if (Response.StatusCode != 401)
            {
                return Task.FromResult<object>(null);
            }
            AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
            if (challenge != null)
            {
                string baseUri = Request.Scheme + Uri.SchemeDelimiter + Request.Host + Request.PathBase;
                string currentUri = baseUri + Request.Path + Request.QueryString;
                string redirectUri = baseUri + Options.CallbackPath;
                AuthenticationProperties extra = challenge.Properties;
                if (string.IsNullOrEmpty(extra.RedirectUri))
                {
                    extra.RedirectUri = currentUri;
                }
                // OAuth2 10.12 CSRF
                GenerateCorrelationId(extra);
                // OAuth2 3.3 space separated                
        string scope = string.Join(" ", Options.Scope);
                // LiveID requires a scope string, so if the user didn't set one we go for the least possible.
        if (string.IsNullOrWhiteSpace(scope))
                {
                    scope = "user-base";
                }
                string state = Options.StateDataFormat.Protect(extra);
                string authorizationEndpoint =
                    Options.AuthorizationEndpoint +
        "?client_id=" + Uri.EscapeDataString(Options.ClientId) +
        "&scope=" + Uri.EscapeDataString(scope) +
        "&response_type=code" +
        "&redirect_uri=" + Uri.EscapeDataString(redirectUri) +
        "&state=" + Uri.EscapeDataString(state);
                var redirectContext = new SimpleSSOAccountApplyRedirectContext(
                    Context, Options,
                    extra, authorizationEndpoint);
                Options.Provider.ApplyRedirect(redirectContext);
            }
            return Task.FromResult<object>(null);
        }
        public async Task<bool> InvokeReturnPathAsync()
        {
            AuthenticationTicket model = await AuthenticateAsync();
            if (model == null)
            {
                _logger.WriteWarning("Invalid return state, unable to redirect.");
                Response.StatusCode = 500;
                return true;
            }
            var context = new SimpleSSOReturnEndpointContext(Context, model);
            context.SignInAsAuthenticationType = Options.SignInAsAuthenticationType;
            context.RedirectUri = model.Properties.RedirectUri;
            model.Properties.RedirectUri = null;
            await Options.Provider.ReturnEndpoint(context);
            if (context.SignInAsAuthenticationType != null && context.Identity != null)
            {
                ClaimsIdentity signInIdentity = context.Identity;
                if (!string.Equals(signInIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal))
                {
                    signInIdentity = new ClaimsIdentity(signInIdentity.Claims, context.SignInAsAuthenticationType, signInIdentity.NameClaimType, signInIdentity.RoleClaimType);
                }
                Context.Authentication.SignIn(context.Properties, signInIdentity);
            }
            if (!context.IsRequestCompleted && context.RedirectUri != null)
            {
                if (context.Identity == null)
                {
                    // add a redirect hint that sign-in failed in some way
                    context.RedirectUri = WebUtilities.AddQueryString(context.RedirectUri, "error", "access_denied");
                }
                Response.Redirect(context.RedirectUri);
                context.RequestCompleted();
            }
            return context.IsRequestCompleted;
        }
        private string GenerateRedirectUri()
        {
            string requestPrefix = Request.Scheme + "://" + Request.Host;
            string redirectUri = requestPrefix + RequestPathBase + Options.CallbackPath; // + "?state=" + Uri.EscapeDataString(Options.StateDataFormat.Protect(state));            
        return redirectUri;
        }
    }
View Code

  1>使用code獲取令牌

  2>獲取用戶信息

  3>SignIn(ExternalCookie)

  4>重新跳轉到http://localhost:6111/login/authsimplesso,回到1.2-2)

 

2、通過authorization code授權模式申請令牌

2.1、Demo展示(這個demo請求實際上是可以跨域的):

2.2、Demo請求流程

1)用戶點擊“通過authorization code授權模式申請令牌”下進入按鈕,使用div加載url地址http://localhost:8550/GrantCode/Authorize?client_id=1&scope=user-base&response_type=code&redirect_uri=http://localhost:6111/api/Code/App1&state={隨機}。如果用戶沒有登錄的情況下請求這個路徑,會跳轉到登錄界面。

2)因為client_id=1應用為可信應用,所以直接生成code,請求http://localhost:6111/api/Code/App1?code=?&state={請求過來的值}

由SimpleSSOOAuthProvider方法AuthorizeEndpoint完成可信應用驗證,用戶令牌信息注冊,SimpleAuthenticationTokenProvider完成code生成

3)/api/Code/App1接收code、state

1)使用code獲取Access_Token

2)使用Access_Token獲取用戶信息

3)使用Refresh_Token刷新Access_Token

4)使用刷新後的Access_Token獲取用戶信息

/api/Code/App1代碼:

        [HttpGet]
        [Route("App1")]
        public async Task<string> App1(string code = "")
        {
            return await AppData(code, "App1", "1", "123");
        }
 private async Task<string> AppData(string code,
            string appName, string clientID, string clientSecret)
        {
            StringBuilder strMessage = new StringBuilder();
            if (!string.IsNullOrWhiteSpace(code))
            {
                string accessToken = "";
                string codeResult = await AuthorizationCode(appName, clientID, clientSecret, code);
                var obj = JObject.Parse(codeResult);
                var refreshToken = obj["refresh_token"].Value<string>();
                accessToken = obj["access_token"].Value<string>();
                strMessage.Append($"<font color='black'><b>應用{appName}使用</b></font></br>code:{code}獲取到</br>refresh_token:{refreshToken}</br>access_token:{accessToken}");
                if (!string.IsNullOrEmpty(accessToken))
                {
                    strMessage.Append($"</br><font color='black'><b>使用AccessToken獲取到信息:</b></font>{ await GetTicketMessageData(accessToken) }");
                    obj = JObject.Parse(await RefreshToken(clientID, clientSecret, refreshToken));
                    refreshToken = obj["refresh_token"].Value<string>();
                    accessToken = obj["access_token"].Value<string>();
                    strMessage.Append($"</br><font color='black'><b>應用{appName}刷新秘鑰獲取到</b></font></br>refresh_token:{refreshToken}</br>access_token:{accessToken}");
                    strMessage.Append($"</br><font color='black'><b>使用刷新後AccessToken獲取到信息:</b></font>{ await GetTicketMessageData(accessToken) }");
                }
            }
            else
            {
                strMessage.AppendLine("獲取code失敗.");
            }
            return await Task.FromResult(strMessage.ToString());
        }
View Code

 

 

3、通過implicit授權模式申請令牌

 3.1、Demo展示:

  

implicit模式是比較特別一種模式,由基於浏覽器應用訪問用戶信息,所以生成的令牌直接為Access_Token,且Url為http://localhost:6111/TokenClient/ShowUser#access_token={0}&token_type={1}&state={2},浏覽器端需要通過window.location.hash訪問。

3.2、Demo請求流程

1)用戶點擊""下進入,http://localhost:8550/GrantCode/Authorize?client_id=2&redirect_uri=http://localhost:6111/TokenClient/ShowUser&response_type=token&scope=user_base&state={隨機}

2)跳轉到用戶授權頁面,用戶授權後,返回http://localhost:6111/TokenClient/ShowUser#access_token={0}&token_type=bearer&state={2}

3)點擊Try Get Data,js使用access_token請求獲取用戶信息。

其中JS代碼:

   $(function () {
            $("#get_data").click(function () {
                var hashDiv = getHashStringArgs();
                var token = hashDiv["access_token"];
                var tokenType = hashDiv["token_type"];
                if (token) {
                    var url = "@ViewBag.ServerTicketMessageUrl";
                    var settings = {
                        type: "GET",
                        url: url,
                        beforeSend: function (request) {
                            request.setRequestHeader("Authorization", tokenType + " " + token);
                        },
                        success: function (data, textStatus) {
                            alert(JSON.stringify(data));
                        }
                    };
                    $.ajax(settings);
                }
            });
        });
        function getHashStringArgs() {
            var hashStrings = (window.location.hash.length > 0 ? window.location.hash.substring(1) : ""),
           hashArgs = {},
           items = hashStrings.length > 0 ? hashStrings.split("&") : [],
           item = null,
           name = null,
           value = null,
           i = 0,
           len = items.length;
            for (i = 0; i < len; i++) {
                item = items[i].split("=");
                name = decodeURIComponent(item[0]);
                value = decodeURIComponent(item[1]);
                if (name.length > 0) {
                    hashArgs[name] = value;
                }
            }
            return hashArgs;
        }
View Code

 

4、通過password模式申請令牌

實現代碼:

      [HttpGet]
        [Route("AppPassword")]
        public async Task<string> AppPassword()
        {
            var clientID = "1";
            var clientSecret = "123";
            var userName = "zfh";
            var password = "123";
            var parameters = new Dictionary<string, string>();
            parameters.Add("grant_type", "password");
            parameters.Add("username", userName);
            parameters.Add("password", password);
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
                "Basic",
                Convert.ToBase64String(Encoding.ASCII.GetBytes(clientID + ":" + clientSecret)));
            var response = await _httpClient.PostAsync(_serverTokenUrl, new FormUrlEncodedContent(parameters));
            var result = await response.Content.ReadAsStringAsync();
            var obj = JObject.Parse(result);
            var refreshToken = obj["refresh_token"].Value<string>();
            var accessToken = obj["access_token"].Value<string>();
            return $"<font color='black'><b>應用App1獲取到用戶zfh的</b></font></br>refresh_token:{refreshToken}</br>access_token:{accessToken}";
        }
View Code

 

5、通過client credentials模式申請令牌

實現代碼:

   [HttpGet]
        [Route("AppclientCredentials")]
        public async Task<string> AppclientCredentials()
        {
            var clientID = "1";
            var clientSecret = "123";
            var parameters = new Dictionary<string, string>();
            parameters.Add("grant_type", "client_credentials");
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
                "Basic",
                Convert.ToBase64String(Encoding.ASCII.GetBytes(clientID + ":" + clientSecret)));
            var response = await _httpClient.PostAsync(_serverTokenUrl, new FormUrlEncodedContent(parameters));
            var result = await response.Content.ReadAsStringAsync();
            var obj = JObject.Parse(result);
            var refreshToken = obj["refresh_token"].Value<string>();
            var accessToken = obj["access_token"].Value<string>();
            return $"<font color='black'><b>應用App1獲取到</b></font></br>refresh_token:{refreshToken}</br>access_token:{accessToken}";
        }
View Code

 

後話

寫的不夠清晰,建議看看源碼。關於OAuth的實現集中在SimpleSSOOAuthProvider,SimpleAuthenticationTokenProvider類。系統有很多不足的地方,後續我會抽時間迭代出一個穩定版本,這次畢竟只花了幾天時間。當然如果您有什麼寶貴建議也可以郵件聯系我。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved