天貓精靈對接2(OAuth 搭建)


根據 接入方式及流程 中的說明,可知,搭建過程中,我們需要自己整一個 OAuth 的授權平台,具體說明可以參考蟋蟀大哥的文章  ASP.NET WebApi OWIN 實現 OAuth 2.0 ,我的實際代碼也是基於文章給出的源碼修改的。

第一步

認真研究一次文檔:

(1)AliGenie在開發商開放平台或者其他第三方平台注冊一個應用,獲取到相應的Client idClient secret

(2)AliGenie 應用向開發商OAuth2.0服務發起一個授權請求

(3)開發商OAuth2.0服務向用戶展示一個授權頁面,用戶可進行登陸授權

(4)用戶授權AliGenie客戶端應用后,進行回跳到AliGenie 的回調地址上並帶上code相關參數

(5)AilGenie回調地址上根據code會去合作方Oauth 的服務上換取 access_token

(6)通過access_token,天貓精靈設備控制時通過該access_token進行訪問合作方的服務

 

關鍵字已經用顏色標明,也就是說,我們需要一個授權平台,授權頁,code 換取 access_token 的功能,分配給 天貓的 clien_id,client_secret.

最主要的還是平台,具體的平台怎么搭建就不說了,參考一下上面給出的鏈接,照着做或者改就行了。

 

因為我們對接天貓精靈主要用的是授權碼模式,所以我們主看授權碼的方式,授權碼模式 的流程請查看 ASP.NET WebApi OWIN 實現 OAuth 2.0 

這兒順便說一下,如果你用的是 .net 4.5 的情況下,安裝 OWIN ,用NuGet安裝時會報錯,提示不兼容對應的框架,所以用控制台安裝舊版的,

  • Owin 對應:  Install-Package Microsoft.Owin -Version 3.1.0
  • Microsoft.Owin.Host.SystemWeb 對應:Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.1.0
  • Microsoft.Owin.Security.OAuth 對應:Install-Package Microsoft.Owin.Security.OAuth -Version 3.1.0
  • Microsoft.Owin.Security.Cookies 對應:Install-Package Microsoft.Owin.Security.Cookies -Version 3.1.0
  • Microsoft.AspNet.Identity.Owin 對應:Install-Package Microsoft.AspNet.Identity.Owin -Version 2.1.0

 

授權頁面

我們直接以對接天貓精靈的流程來簡單說一下代碼應該怎么改吧。

根據官方文檔提示,我們要給他天貓精靈配置一個 client_id ,client_secrete,檢查源碼知道,它已經默認寫死了,client_id=xishuai,client_secrete=123  .我們先記下,等會再配置。

按着天貓精靈的流程,我們還需要一個 適配手機端訪問的授權的 H5 頁,那我們添加一個控制器(Home),加個 Index 方法用來返回視圖,再加一個 Index2 准備用來接收它提交過來的數據,再給它加個視圖,名字就定為 Index ,在里面放上幾個 input 標簽,准備用來存放天貓傳過來的參數的(后續再隱藏起來),樣式就先不處理了,晚點再說。

控制器:

        public ActionResult Index()
        {
            return View();
        }


        [HttpPost]
        public ActionResult Index2()
        {
            return View();
        }

視圖:

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div> 
        <form id="form1" method="post" action="@Url.Action("Index2")">
            <input type="text" name="clientId" value="xishuai" />
            <br />
            <input type="text" name="redirect_uri" value="" />
            <br />
            
            <input type="text" name="response_type" value="" />
            <br />
            <input type="text" name="state" value="" />
            <br />
            <input type="submit" value="提交" />
        </form>
        
    </div>
</body>
</html>

看一下 官方文檔-接入方式及流程 ,在第5點得知,請求的鏈接如下:

原文檔鏈接:https://xxx.com/auth/authorize?redirect_uri=https%3A%2F%2Fopen.bot.tmall.com%2Foauth%2Fcallback%3FskillId%3D11111111%26token%3DXXXXXXXXXX&client_id=XXXXXXXXX&response_type=code&state=111
對應到我們這兒的鏈接將會是:
https://xxx.com/Home/Index?redirect_uri=https%3A%2F%2Fopen.bot.tmall.com%2Foauth%2Fcallback%3FskillId%3D11111111%26token%3DXXXXXXXXXX&client_id=XXXXXXXXX&response_type=code&state=111

redirect_uri: 處理完成的返回地址,這個我們不應該去動它.
client_id: 在合作方上注冊的應用Id(也就是我們剛才說到的准備給他配置的那個 client_id 值:xishuai )

state: 在我代碼中,我是直接無視了這個參數的。項目目前沒有用到它。

 

既然知道有這么多參數,那我們整理一下,在控制器接收一下,返回到視圖界面對應的地方吧.代碼如下:

Home 控制器中的 Index 方法:

        public ActionResult Index()
        {
            string clientId = Request.QueryString["client_id"] + "";
            string redirect_uri = Request.QueryString["redirect_uri"] + "";
            string response_type = Request.QueryString["response_type"] + "";
            string state = Request.QueryString["state"] + "";
           
            ViewBag.clientId = clientId;
            ViewBag.redirect_uri = redirect_uri;
            ViewBag.response_type = response_type;
            ViewBag.state = state;

            return View();
        }

Index 視圖:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div> 
        <form id="form1" method="post" action="@Url.Action("Index2")">
            <input type="text" name="clientId" value="@ViewBag.clientId" />
            <br />
            <input type="text" name="redirect_uri" value="@ViewBag.redirect_uri" />
            <br />
            <input type="text" name="response_type" value="@ViewBag.response_type" />
            <br />
            <input type="text" name="state" value="@ViewBag.state" />
            <br />
            <input type="submit" value="提交" />
        </form>
        
    </div>
</body>
</html>

我們看一下測試用例的代碼,其中 OAuth_AuthorizationCode_Test 測試用例對應着授權碼模式,也就是說,我們需要看下它原本是怎么請求的,依葫蘆畫瓢,簡單過一篇代碼之后,發現 GetAuthorizationCode() 這個方法很可疑,跟進去,可以看到,它確實是發起了請求授權服務。我們簡單分析一下,它利用 HttpClient 發起了一個 /authorize 請求,傳遞了grant_type,response_type,client_id,redirect_uri 這幾個參數,也就是說,我們也可以模仿他這樣操作,那么在  Index2 方法中這樣寫:

        public async Task<ActionResult> Index2()
        {
            string clientId = Request.Form["clientId"] + "";
            string redirect_uri = Request.Form["redirect_uri"] + "";
            string state = Request.Form["state"] + "";
            string urlEncode = HttpUtility.UrlEncode(redirect_uri);
            return Redirect("~/authorize?grant_type=authorization_code&response_type=code&client_id="+clientId+"&redirect_uri="+urlEncode);
        }

因為我們是在同一個服務器,所以我們不再用 HttpClient 去發起請求了,直接上跳轉。

直接更新上服務器,並上 天貓的控制台 填寫 信息,

賬戶授權鏈接填入: https://YourWebSite/Home/Index

ClientID填入:xishuai

Client Secret 填入:123

Access Token URL 填入:https://YourWebSite/NoAddress (隨便寫一個,只是為了先測試第一步是不是正常的先)

廠商登出 URL 留空。

更新上服務器,進入 天貓控制台 中的測試驗證,然后點擊 賬戶授權 ,會發現報錯!!!提示缺少參數。那我們檢查一下代碼吧,看下是哪里出的問題,缺少參數,也就是說,我們返回給天貓的URL,參數寫少了,或者寫錯了。我們檢查一下。

打開 OpenAuthorizationServerProvider 找到 AuthorizeEndpoint 方法(它是對應着 authorize 請求的處理),可以看到里面有個 redirectUri 的數據,用日志的方式輸出來看下(其實不用看了,剛才我們在測試的時候,你直接把 <input type="text" name="redirect_uri" /> 的值復制出來就知道問題出在哪了),redirectUri 在此處的值為:https://open.bot.tmall.com/oauth/callback?skillId=11111111&token=XXXXXXXXXX ,看到這兒,我想結合代碼就知道問題出在哪了吧,源碼如下:

context.Response.Redirect(redirectUri + "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token));

修改如下:

        /// <summary>
        /// 生成 authorization_code(authorization code 授權方式)、生成 access_token (implicit 授權模式)
        /// </summary>
        public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
        {
            if (context.AuthorizeRequest.IsImplicitGrantType)
            {
                //implicit 授權方式
                var identity = new ClaimsIdentity("Bearer");
                context.OwinContext.Authentication.SignIn(identity);
                context.RequestCompleted();
            }
            else if (context.AuthorizeRequest.IsAuthorizationCodeGrantType)
            {
                //authorization code 授權方式
                var redirectUri = context.Request.Query["redirect_uri"];
                var clientId = context.Request.Query["client_id"];

                
                var identity = new ClaimsIdentity(new GenericIdentity(
                    clientId, OAuthDefaults.AuthenticationType));

                var authorizeCodeContext = new AuthenticationTokenCreateContext(
                    context.OwinContext,
                    context.Options.AuthorizationCodeFormat,
                    new AuthenticationTicket(
                        identity,
                        new AuthenticationProperties(new Dictionary<string, string>
                        {
                            {"client_id", clientId},
                            {"redirect_uri", redirectUri}
                        })
                        {
                            IssuedUtc = DateTimeOffset.UtcNow,
                            ExpiresUtc = DateTimeOffset.UtcNow.Add(context.Options.AuthorizationCodeExpireTimeSpan)
                        }));

                await context.Options.AuthorizationCodeProvider.CreateAsync(authorizeCodeContext);


                var ResUrl = redirectUri;
                if (redirectUri.Contains("?"))
                {
                    ResUrl += "&code=" + Uri.EscapeDataString(authorizeCodeContext.Token);
                }
                else
                {
                    ResUrl += "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token);
                }
                

                //writeLog("ResUrl", ResUrl,"TestToken");
               // writeLog("Token", authorizeCodeContext.Token, "TestToken");
                
                context.Response.Redirect(ResUrl);
                context.RequestCompleted();
            }
        }

這樣,就能正常的處理跳轉的參數了。更新上服務器,測試,通過!沒有提示缺少參數了。但現在提示取不到 access_token 了。也就是說我們到了處理 獲取 access_token 這一步了。

獲取 access_token 

我們回頭繼續看下那個測試用例(OAuth_AuthorizationCode_Test),

        [Fact]
        public async Task OAuth_AuthorizationCode_Test()
        {
            var authorizationCode = GetAuthorizationCode().Result; //獲取 authorization_code

            var tokenResponse = GetToken("authorization_code", null, null, null, authorizationCode).Result; //根據 authorization_code 獲取 access_token
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenResponse.AccessToken);

            var response = await _httpClient.GetAsync($"/api/values");
            if (response.StatusCode != HttpStatusCode.OK)
            {
                Console.WriteLine(response.StatusCode);
                Console.WriteLine((await response.Content.ReadAsAsync<HttpError>()).ExceptionMessage);
            }
            Console.WriteLine(await response.Content.ReadAsStringAsync());
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            Thread.Sleep(10000);

            var tokenResponseTwo = GetToken("refresh_token", tokenResponse.RefreshToken).Result; //根據 refresh_token 獲取 access_token
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenResponseTwo.AccessToken);
            var responseTwo = await _httpClient.GetAsync($"/api/values");
            Assert.Equal(HttpStatusCode.OK, responseTwo.StatusCode);
        }

在獲取了 authorization_code 之后,調用了 GetToken 方法,查看 GetToken 方法

        private static async Task<TokenResponse> GetToken(string grantType, string refreshToken = null, string userName = null, string password = null, string authorizationCode = null)
        {//"authorization_code", null, null, null, authorizationCode
            var clientId = "xishuai";
            var clientSecret = "123";
            var parameters = new Dictionary<string, string>();
            parameters.Add("grant_type", grantType);

            if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
            {
                parameters.Add("username", userName);
                parameters.Add("password", password);
            }
            if (!string.IsNullOrEmpty(authorizationCode))
            {
                parameters.Add("code", authorizationCode);
                parameters.Add("redirect_uri", "http://localhost:8333/api/authorization_code"); //和獲取 authorization_code 的 redirect_uri 必須一致,不然會報錯
            }
            if (!string.IsNullOrEmpty(refreshToken))
            {
                parameters.Add("refresh_token", refreshToken);
            }

            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
                "Basic",
                Convert.ToBase64String(Encoding.ASCII.GetBytes(clientId + ":" + clientSecret)));

            var response = await _httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters));
            var responseValue = await response.Content.ReadAsStringAsync();
            if (response.StatusCode != HttpStatusCode.OK)
            {
                Console.WriteLine(response.StatusCode);
                Console.WriteLine((await response.Content.ReadAsAsync<HttpError>()).ExceptionMessage);
                return null;
            }
            return await response.Content.ReadAsAsync<TokenResponse>();
        }

構建了一個 HttpClient ,組好參數 post 給 /token  .那我們還是依葫蘆畫瓢,照抄過來用看下。在 Home 控制器下,定義一個 TestToken 方法,再看下官方文檔

(B) 通過code換取合作方訪問令牌
例:
https://XXXXX/token?grant_type=authorization_code&client_id=XXXXX&client_secret=XXXXXX&code=XXXXXXXX&redirect_uri=https%3A%2F%2Fopen.bot.tmall.com%2Foauth%2Fcallback
請求方法: POST

參數說明:
client_id: 在合廠商平台上注冊的應用Id
grant_type: 授權類型 authorization_code
client_secret:在廠商平台上注冊應用的secret
code: 授權登陸后回調AliGenie的地址返回的code
redirect_uri: AliGenie回調地址

也就是說,它會發這些參數給我們,那么我們就用 Request.Form 一一接收,然后模仿着GetToken 的方法寫。

TestToken 方法如下:

        public async Task<ActionResult> TestToken()
        {
            string grant_type = Request.Form["grant_type"] + "";
            string client_id = Request.Form["client_id"] + "";
            string client_secret = Request.Form["client_secret"] + "";
            string code = Request.Form["code"] + "";
            string redirect_uri = Request.Form["redirect_uri"] + "";

            var parameters = new Dictionary<string, string>();
            parameters.Add("grant_type", grant_type);
            parameters.Add("code", code);
            parameters.Add("redirect_uri", redirect_uri);


            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
           
            HttpClient _httpClient = new HttpClient();
            _httpClient.BaseAddress = new Uri(System.Configuration.ConfigurationManager.AppSettings["serverUrl"]);//從配置文件中讀取,服務器的域名
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
                "Basic",
                Convert.ToBase64String(Encoding.ASCII.GetBytes(client_id + ":" + client_secret)));

            var response = await _httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters));
            var responseValue = await response.Content.ReadAsStringAsync();

       writeLog("responseValue",resp,"responseValue");

            if (response.StatusCode != HttpStatusCode.OK)
            {
                return Json(new TaskResponseError
                {
                    error = response.StatusCode + "",
                    error_description = (await response.Content.ReadAsAsync<HttpError>()).ExceptionMessage
                });
            }
            var TokenResponse = await response.Content.ReadAsAsync<TokenResponseRight>();

            TokenResponse.expires_in = Convert.ToInt64(System.Configuration.ConfigurationManager.AppSettings["tokenExpiresTime"]);//過期時間也要返回
            writeLog("TokenResponse:", JsonConvert.SerializeObject(TokenResponse) + "", "TestToken");
            return Content(JsonConvert.SerializeObject(TokenResponse), "application/json");//強行指定類型,官方文檔特別提示要用 application/json ,之前試過用return Json(xxx); 返回 之后提示參數錯誤之類的。
        }

OK,更新上服務器,再上 天貓控制台 ,把 Access Token URL 修改一下,修改為:https://YourWebSite/Home/TestToken ,測試跑起來。測試應該是通過的,如果還有問題可以問一下我,2018年6月1日11:47:55 昨天到現在 真機測試的功能 AliGenie 還沒修復好,所以我也不好截圖給你們看,回頭再來補充吧。

 

refalsh Token 的功能

查看 官方文檔 

(C) 通過refresh_token刷新access_token(該功能已上線,請確保廠商自己的刷新功能是完善的)
例:
https://XXXXX/token?grant_type=refresh_token&client_id=XXXXX&client_secret=XXXXXX&refresh_token=XXXXXX

請求方法: POST

 
參數說明:
   grant_type:更新access_token的授權方式為refresh_token
   client_id: 在廠商平台上注冊的應用Id
   client_secret:在廠商平台上注冊應用的secret
   refresh_token: 上一次授權獲取的refresh_token
 
注:示例中的鏈接API( https: //XXXXX/token) 為開放平台中的Access Token Url 字段。

得知,刷新 token 的功能是和我們的在 控制台中填寫的 Access Token Url 是同一個入口,也就是說,我們需要對 TestToken 方法進行改造,讓它也可以處理 刷新 token 的操作。

再查看那個測試用例(OAuth_AuthorizationCode_Test),可以看到以下代碼

 Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            Thread.Sleep(10000);

            var tokenResponseTwo = GetToken("refresh_token", tokenResponse.RefreshToken).Result; //根據 refresh_token 獲取 access_token
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenResponseTwo.AccessToken);

測試代碼中休眠了10秒之后,去刷新 token 的操作,GetToken 方法我們之前已經看過了,知道它是做什么操作的,那么我們就直接在 TestToken 里面改造一下:

        public async Task<ActionResult> TestToken()
        {
            string grant_type = Request.Form["grant_type"] + "";
            string client_id = Request.Form["client_id"] + "";
            string client_secret = Request.Form["client_secret"] + "";
            string code = Request.Form["code"] + "";
            string redirect_uri = Request.Form["redirect_uri"] + "";
            string refreshToken = Request.Form["refresh_token"] + "";//取refreshToken 參數    之前這兒寫錯了,如有人使用此段代碼,麻煩改正一下
            //https://XXXXX/token?grant_type=refresh_token&client_id=XXXXX&client_secret=XXXXXX&refresh_token=XXXXXX

            var parameters = new Dictionary<string, string>();
            parameters.Add("grant_type", grant_type);

            parameters.Add("code", code);

            parameters.Add("redirect_uri", redirect_uri);



            if (!string.IsNullOrEmpty(refreshToken))
            {//加入判斷,當有此字段時,則為刷新 token 的操作
                parameters.Add("refresh_token", refreshToken);
            }

            System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls;
            

            HttpClient _httpClient = new HttpClient();



            _httpClient.BaseAddress = new Uri(System.Configuration.ConfigurationManager.AppSettings["serverUrl"]);
            _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(
                "Basic",
                Convert.ToBase64String(Encoding.ASCII.GetBytes(client_id + ":" + client_secret)));

            var response = await _httpClient.PostAsync("/" + System.Configuration.ConfigurationManager.AppSettings["serverExtUrlParam"] + "/token", new FormUrlEncodedContent(parameters));
            var responseValue = await response.Content.ReadAsStringAsync();



            if (response.StatusCode != System.Net.HttpStatusCode.OK)
            {
                return Json(new TaskResponseError
                {
                    error = response.StatusCode + "",
                    error_description = (await response.Content.ReadAsAsync<System.Web.Http.HttpError>()).ExceptionMessage
                });
            }
            var TokenResponse = await response.Content.ReadAsAsync<TokenResponseRight>();

            TokenResponse.expires_in = Convert.ToInt64(System.Configuration.ConfigurationManager.AppSettings["tokenExpiresTime"]);


            if (grant_type == "authorization_code")
            {
                string hostId = CloudApi.Providers.OpenAuthorizationCodeProvider.GetHostIDByAuthenticationCode(code);
                if (!string.IsNullOrEmpty(hostId))
                {
                    CloudApi.Providers.OpenAuthorizationCodeProvider.SetHostIDAndTicket(hostId, TokenResponse.AccessToken);
                }
            }

            ToolHelper.FuntionHelper.writeLog("TokenResponse:", JsonConvert.SerializeObject(TokenResponse) + "", "TestToken");
            return Content(JsonConvert.SerializeObject(TokenResponse), "application/json");
        }

 

 

 

OAuth 的授權平台,就這樣簡單搭建好了,剩下的就是開發者自己去完善實際的功能,比如授權用的 ClientID,Client_Secrete 應該從數據庫里取、還是直接從配置文件中讀取出來。授權成功了,你怎么判斷是誰,

現在時間是:2018年6月1日14:36:53 ,AliGenie 的真機測試還是用不了,所以也是沒辦法給你們展示實際的效果。這個也是蛋蛋的憂傷。

 

 

Q & A:

Q1.我這個流程走是沒問題,但我不知道實際操作的時候應該取哪個賬戶的設備數據啊?

A1:這個問題在你授權登錄那 H5 頁面,自行解決,加個賬戶密碼,讓用戶自己登錄,具體邏輯自己處理下就可以了,其他要修改的地方,可能是在 OpenAuthorizationCodeProvider 這個類里面,你要加一個靜態的 ConcurrentDictionary ,用來存放是哪個用戶授權的,對應的 token 是什么。

代碼如下:

    public class OpenAuthorizationCodeProvider : AuthenticationTokenProvider
    {
        private readonly ConcurrentDictionary<string, string> _authenticationCodes = new ConcurrentDictionary<string, string>(StringComparer.Ordinal);


//主機ID 對應着你的用戶名
        public static ConcurrentDictionary<string, string> HostIdAndAuthenticationCodeCache = new ConcurrentDictionary<string, string>(StringComparer.Ordinal);
//我這兒記錄了主機ID和授權碼

        public static ConcurrentDictionary<string, string> HostIdAndTicketCache = new ConcurrentDictionary<string, string>(StringComparer.Ordinal);

//這兒記錄了主機ID和 token

        public static string GetHostIDByAuthenticationCode(string authenticationCode)
        {
            var tempItem = HostIdAndAuthenticationCodeCache.FirstOrDefault(c => c.Value.Equals(authenticationCode, StringComparison.OrdinalIgnoreCase));
            if (tempItem.Key != null)
            {
                return tempItem.Key;
            }
            else
            {
                return "";
            }
        }




        public static void SetHostIDAndTicket(string hostId, string ticket)
        {
            HostIdAndTicketCache.AddOrUpdate(hostId, ticket, (k, ov) => ov = ticket);
        }



        public static string GetHostIdByTicket(string ticket)
        {
            var tempItem = HostIdAndTicketCache.FirstOrDefault(c => c.Value.Equals(ticket, StringComparison.OrdinalIgnoreCase));
            if (tempItem.Key != null)
            {
                return tempItem.Key;
            }
            else
            {
                return "";
            }
        }





        /// <summary>
        /// 生成 authorization_code
        /// </summary>
        public override void Create(AuthenticationTokenCreateContext context)
        {
            context.SetToken(Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"));

            string TempTicket = context.SerializeTicket();
            _authenticationCodes.AddOrUpdate(context.Token, TempTicket, (k, ov) => ov = TempTicket);
            //_authenticationCodes[context.Token] = context.SerializeTicket();
            


            string hostId = context.Request.Query["hostId"];

            HostIdAndAuthenticationCodeCache.AddOrUpdate(hostId, context.Token, (k, ov) => ov = context.Token);//將 主機ID 保存起來
        }



        /// <summary>
        /// 由 authorization_code 解析成 access_token
        /// </summary>
        public override void Receive(AuthenticationTokenReceiveContext context)
        {
            string value;
            if (_authenticationCodes.TryRemove(context.Token, out value))
            {
                context.DeserializeTicket(value);
            }
        }


    }
View Code

Q2:為什么我明明返回給天貓精靈 authorize code 了,它第二次來請求 token 的時候,就是死活沒找到?

A2: 檢查一下,第一步返回時的參數 redirect_url 是什么,他第二次請求過來的參數 return_url 是什么。(我就因為把state 在第一步的時候也返回回去了,導致第二步死活取不到 token)

 

 

2018-7-16 14:47:12 補充:

實際用的過程中,你需要保存用戶ID、refresh_token 這些數據,請自行處理,在我實際代碼中,用的是 Redis。用來保存了refresh_token和用戶標識。

上面代碼中,有一段 用到的 refresh_token 接收的時候寫錯了,寫成了 refreshtoken。導致刷新 token 功能有問題。請之前用的人注意一下。還是太相信自己的代碼,導致出bug ,測試的時候就看着自己寫的代碼測試.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM