10)ABP實(shí)現(xiàn)集成openiddict的第三方授權(quán)登錄(github)&UI授權(quán)登錄
上章我們已經(jīng)可以請(qǐng)求獲取到了授權(quán)用戶(hù)的信息,只不過(guò)沒(méi)有把信息暫存到實(shí)體中。
由于我們是多平臺(tái)的授權(quán)登錄,每個(gè)平臺(tái)之間返回的數(shù)據(jù)類(lèi)型有所差異,所有這里統(tǒng)一定義了我需要的核心數(shù)據(jù)?AuthUserBaseInfo
,同時(shí)平臺(tái)之間返回的字段差異需要有地方映射?AuthUserBaseInfo
里面字段,進(jìn)而定義了?IAuthUserInfoFieldMap
的 FieldMap()方法, 代碼如下:
在?YiAim.Cms.Application.Contracts
里面新建
github通過(guò)授權(quán)獲取的用戶(hù)信息轉(zhuǎn)換成功GithubAuthDto
可以看到github里面返回的沒(méi)有是login字段,沒(méi)有UserName,所有這里我將login賦值給UserName。同時(shí)在FieldMap里面賦值給了NickName(因?yàn)樵趃ithub里面返回沒(méi)有找到合適的字段)
在?YiAim.Cms.Application
?里面的?GithubService
?修改返回類(lèi)型
在 ThirdOAuthServiceBase 抽象類(lèi)里面的?GetUserByOAuthAsync
方法為AccessToken
屬性賦值
????
在AuthorizeService
里面,實(shí)現(xiàn)了IAuthorizeService相關(guān)的接口,最后返回用戶(hù)信息時(shí)一定要調(diào)用FieldMap()
,統(tǒng)一映射AuthUserBaseInfo
對(duì)象
?
實(shí)現(xiàn)的效果

接下來(lái)進(jìn)行數(shù)據(jù)遷移生成第三方授權(quán)表AppUserThirdAuth
,同時(shí)將curd的方法補(bǔ)齊。
切到vue項(xiàng)目里面
先把登錄頁(yè)面的第三方授權(quán)登錄入口加入

???
在src\identity里新建auth.js
auth.js
去到github里面將跳轉(zhuǎn)回調(diào)地址改成?http://localhost:9527/#auth-redirect
?跳轉(zhuǎn)回到vue項(xiàng)目里面,同時(shí)不要忘記看看vue里面對(duì)應(yīng)的路由是否存在,不存在則補(bǔ)上;permission.js
里面要將auth-redirect放到whiteList數(shù)組里面解除驗(yàn)證。

修改登錄流程,通過(guò)openiddict的/connect/token
完成第三方授權(quán)同時(shí)返回token
本來(lái)我是想像identityServer
那樣簡(jiǎn)單配置擴(kuò)展登錄項(xiàng)就可以了,事實(shí)證明我還是太年輕了。 先來(lái)看一下IdentityServer4通過(guò)/connect/token
獲取token
IdentityServer4通過(guò)GrantType來(lái)區(qū)分不同的授權(quán)方式,除了常規(guī)的授權(quán)方式之外,在defaut條件中,有自定義授權(quán)生成token的方式(ProcessExtensionGrantRequestAsync),可以通過(guò)這種方式集成其他方式驗(yàn)證比如:微信登陸、短信登陸等等;
簡(jiǎn)單實(shí)現(xiàn)如下:1、自定義授權(quán)實(shí)現(xiàn)繼承IExtensionGrantValidator
并實(shí)現(xiàn)ValidateAsync方法 2、添加擴(kuò)展方法 3、種子數(shù)據(jù)添加grantTypes
核心代碼如下
在配置中注入擴(kuò)展方法
添加種子數(shù)據(jù)
通過(guò)上述方法就可以實(shí)現(xiàn)IdentityServer4的擴(kuò)展登錄,那么openiddict應(yīng)該也支持?jǐn)U展方式實(shí)現(xiàn),在查看openiddict
文檔(https://documentation.openiddict.com/),我是沒(méi)有找到類(lèi)似IdentityServer4擴(kuò)展方法。openiddict默認(rèn)實(shí)現(xiàn)了五種獲取token的方式。在文檔中沒(méi)有找到只能去看看一下源碼,在abp源碼里面打開(kāi)openiddict的源碼,發(fā)現(xiàn)確實(shí)是支持?jǐn)U展的方式。

興奮了一小會(huì)~ 開(kāi)干,按照IdentityServer方式繼續(xù)ITokenExtensionGrant
實(shí)現(xiàn)一個(gè)類(lèi)似。調(diào)試的時(shí)候發(fā)現(xiàn)都不觸發(fā),我是這樣注入

也許是我的實(shí)現(xiàn)或者注入的方式錯(cuò)了,反正搞了兩天嘗試Google、百度搞了N種方式,最后直接放棄該方法。最后想直接修改源代碼不是來(lái)得更簡(jiǎn)單,回到openiddict源碼中發(fā)現(xiàn)?TokenController
是個(gè)部分類(lèi)同時(shí)HandleAsync
是個(gè)虛擬方法允許重寫(xiě)。 在stackoverflow里面還發(fā)現(xiàn)別人很多年前使用Google Auth with OpenIdDictServer實(shí)現(xiàn)方式可以借鑒一下(https://stackoverflow.com/questions/41223694/rich-twitter-digits-google-auth-with-openiddictserver)
在YiAim.Cms.HttpApi里的Controllers新建YiAimTokenController,繼承TokenController以保留原有的功能
這里要將路由重寫(xiě)不能使用原路由/connect/token
,就算你將路由的order=-1一樣不行。路由重寫(xiě)之后還需要 (CmsWebModule)?ConfigureServices(ServiceConfigurationContext context)
方法里面配置如下
SetTokenEndpointUri一定設(shè)置跟路由對(duì)應(yīng)的,不然會(huì)出現(xiàn)錯(cuò)誤An OpenID Connect response cannot be returned from this endpoint
,我在stackoverflow得到解釋?zhuān)?OpenIddict 配置了/connect/token作為令牌端點(diǎn)地址,如果地址與注冊(cè)端點(diǎn)路徑不同,OpenIddict不處理該請(qǐng)求并拒絕將其視為令牌請(qǐng)求?詳情見(jiàn)(https://stackoverflow.com/questions/42048770/asp-net-core-openiddict-throws-an-openid-connect-response-cannot-be-returned-fr)
下面是我項(xiàng)目實(shí)現(xiàn)的邏輯代碼,其他更多方式可以O(shè)penIddict源碼里面token的實(shí)現(xiàn)
回到vue里面把登錄頁(yè)面(src\views\index.vue)和src\store\user.js優(yōu)化一下, index.vue里面賬戶(hù)密碼登錄和第三方授權(quán)登錄都統(tǒng)一采用this.$store.dispatch("user/login", clientSetting)
實(shí)現(xiàn),store\user.js里面直接傳參數(shù)進(jìn)入。
最后來(lái)測(cè)試一下
測(cè)試前先要在openiddictapplications
表中添加授權(quán)數(shù)據(jù),可以直接在表中添加也可使用數(shù)據(jù)遷移方式添加


運(yùn)行項(xiàng)目測(cè)試,可以看到直接提示為綁定xxx。這個(gè)結(jié)果就是正確的預(yù)期,因?yàn)榈谌绞跈?quán)表里沒(méi)有數(shù)據(jù)。第三方授權(quán)表的數(shù)據(jù)可以給定一個(gè)綁定界面從綁定界面寫(xiě)入綁定關(guān)系即可,這里就不實(shí)現(xiàn)了。

我直接從數(shù)據(jù)庫(kù)里面添加一條我的GitHub綁定關(guān)系再看效果

總結(jié)
到此第三方github集成openiddict授權(quán)登錄的功能&UI授權(quán)登錄已經(jīng)完成了。其中還有挺多的細(xì)節(jié)需要優(yōu)化的比如:accesstoken的有效期(微信公眾號(hào)的accesstoken為兩個(gè)小時(shí)且一天之中有請(qǐng)求次數(shù)限制),實(shí)際項(xiàng)目中這些都是需要做處理的問(wèn)題。在使用openiddict的過(guò)程中遇到了挺多的問(wèn)題,加上openiddict的相關(guān)資料基本都是英文而且案例也少同時(shí)個(gè)人水平有限,所以難度又增加了億點(diǎn)點(diǎn)。所幸的是花費(fèi)了幾天的時(shí)間終于完成了這個(gè)功能點(diǎn)。期待.NET的生態(tài)越來(lái)越好。