從壹開始 [ Ids4實戰 ] 之七 ║ 客戶端、服務端、授權中心全線打通


1、經過元旦兩天的全力整改,終於在這新的一年,完成了我的布道生涯的第一個大步走 —— 那就是客戶端(VUE)、服務端(ASP.NET Core API)、授權中心(IdentityServer4)的大融合,不僅有文檔也有代碼,更重要的是實戰。

2、這一大步里邊當然也有很多小步驟,知識點就不說了,過去的文章里都有。

3、具體的代碼和效果呢,我會在下邊給大家先簡單的說明一下,今天的目的主要是第一篇,概述下,里邊的小知識點或者注意事項,其實主要還是Ids4的內容,我還是會慢慢的在以后的文章或者視頻中,給大家講解的。

4、有人問了我的新年計划,主要是CI/CD這一塊,配合Docker和DDD,實現第二個閉環,具體還沒有想好,等我通知吧。

 

那下邊我就簡單的說說效果吧,大家也可以自行體驗一下:

http://vueadmin.neters.club

(支持滑動更新等基本操作,后期增加單點登錄)

 

一、Blog.Admin 客戶端

Admin項目,是基於Vue+Ele開發的一套后端權限框架,是我自主研發的,里邊主要是用到了動態數據庫授權認證,使用JWT的復雜策略授權技術,精確到按鈕基本,目前部門數據權限還在設計當中,以后也會附加上,這是內部授權這一塊,但是認證想做一個統一認證中心,所以就想到了IdentityServer4了。

 

Vue項目和其他的SPA項目是一樣的,連接IdentityServer4認證中心,主要是通過oidc-client這個插件來處理的,

npm install oidc-client --save

 

用法其實很簡單,我簡單說下思路,具體的看我的代碼,或者看官網都可以:

 

 class ApplicationUserManager extends UserManager {
  constructor () {
    super({
      authority: 'http://ids.neters.club',
      client_id: 'blogadminjs',
      redirect_uri: 'http://vueadmin.neters.club/callback',
      response_type: 'id_token token',
      scope: 'openid profile roles blog.core.api',
      post_logout_redirect_uri: 'http://vueadmin.neters.club'
    })
  }

 

 

 

這個是核心方法,目的是通過配置,實現用戶管理,比如登錄,跳轉,回調,獲取用戶信息,令牌token,刷新等等,當然以后可能會配合單點登錄做處理。

 

  methods: {
    async refreshUserInfo() {
      const user = await applicationUserManager.getUser();
      if (user) {
        this.user.name = user.profile.name;
        this.user.isAuthenticated = true;
      } else {
        this.user.name = "";
        this.user.isAuthenticated = false;
      }
    }
  }

 

 

 

這個是使用上邊的UserManager來處理遠程獲取到的用戶數據。

具體的代碼我已經放到了Blog.Admin項目的ids4分支下了:

 

 

 

 

 

二、Blog.Core 資源服務端

這個項目想必都知道了,不多說什么,其實你的任意一個后端服務項目都可以,只要做個表結構,然后配置Identityserver4的認證即可。

 

//2.2【認證】、IdentityServer4 認證 (暫時忽略)
services.AddAuthentication("Bearer")
  .AddIdentityServerAuthentication(options =>
  {
      options.Authority = "http://ids.neters.club";
      options.RequireHttpsMetadata = false;
      options.ApiName = "blog.core.api";
  });

 

 

 

這個就是一個核心的代碼,將我們BlogCore的資源服務器認證方式,從JWT改成Ids4認證

 

 

 

修改完認證方式以后,下邊就是簡單的對其中幾個小知識點進行微調了,比如某些Claim聲明字段,我用的和Ids4不太一樣,所以就簡單微調一下,主要的修改內容,我也新建了一個分支,可以自行查看下,修改的地方不多。

 

 

 

 

 

三、Blog.Idp 認證授權中心

這個才是整個項目的重頭戲,項目的重中之重,不過配置起來也不難,具體的操作和使用,我也在錄視頻和寫文章,其實只要了解這幾個知識點,就基本學會了Ids4了:

1、如何引用指定的nuget包;

2、JWT、OpenID、OAuth2、OIDC 四者的關系和內容;

3、常見的四種授權方式:簡化、混合、密碼、客戶端等要明白場景,會用;

4、學會聯調;

具體的就不多說了,不是今天的講解內容。今天主要點一下部署的時候的幾個知識點,其他的看我的代碼即可,這次是master分支。

 

// 使用證書,可以直接使用開發證書
builder.AddDeveloperSigningCredential();

// 或者自己配置
.AddDeveloperSigningCredential(true, ConstanceHelper.AppSettings.CredentialFileName)
.AddSigningCredential(new X509Certificate2(Path.Combine(Environment.WebRootPath,
        Configuration["Certificates:Path"]),
        Configuration["Certificates:Password"]))

 

 

 

證書這個很重要,當然既然是安全,就要好好處理,可以配合的證書,繼續搞搞HTTPS安全協議,未來還是很多要處理的。

 

 new Client {
     ClientId = "blogadminjs",
     ClientName = "Blog.Admin JavaScript Client",
     AllowedGrantTypes = GrantTypes.Implicit,
     AllowAccessTokensViaBrowser = true,

     RedirectUris =           { "http://vueadmin.neters.club/callback" },
     PostLogoutRedirectUris = { "http://vueadmin.neters.club" },
     AllowedCorsOrigins =     { "http://vueadmin.neters.club" },

     AllowedScopes = {
         IdentityServerConstants.StandardScopes.OpenId,
         IdentityServerConstants.StandardScopes.Profile,
         "roles",
         "blog.core.api"
     }
 }

 

 

 

這是另一個重點,必須要配置客戶端,不僅是數據生成到數據庫,更是在授權的時候,起到安全的作用。

 

最后一個小問題,確定是我自己的問題,就是部署的時候,我本來用的Nginx進行代理,但是配置文件里,卻依然是localhost:

 

 

 

這樣就導致了一個問題,雖然我的認證中心項目可以正常的跑,我是說服務器生產環境,但是用客戶端去登錄的時候,會自動跑到locaohost里,畢竟配置文件是這樣的。

網上找了很多資料,都是本地教程,部署的都很少,我也是很方,最后我找到了官方的一個在線demo項目,它是正常的,我仔細研究了下代碼,代碼和我的沒啥區別,最后靈機一動,我看了看他們的服務器,是IIS!我趕緊實驗了一番,還真的是正常了:

 

 

 

 

 

但是這個不科學呀,這個我要承認下,肯定是我學藝不精,Nginx肯定是可行的,但是我沒有找到為何去配置,這個時候應該查看官網的,當我繼續在尋找的時候,但是正好有一個小伙伴的小伙伴告訴了我,賊簡單,這個故事告訴我們,學習知識要從細節着手,不能知其然而不知其所以然。

 var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; options.IssuerUri = "http://ids.neters.club";// 就是這里 options.PublicOrigin = "http://ids.neters.club";     })

 

結果還是正確的,看來還是要多讀文檔,當然如果實在是繞不過來,也可以先求助。

 

 

 

就這樣,元旦一整天就過去了,項目也終於放上去了,當然還有很多要優化的,比如如何在Nginx部署IdentityServer的時候配置HTTPS協議,既然開始了,便只顧風雨兼程了。

 

 

四、遇到了問題

1、手機版兼容,登錄不跳轉

 本以為上邊的已經完成了,電腦上,也各種測試沒問題,就在下班的路上,在手機上試試吧,竟然無效?!無法跳轉。真是尷尬

夜里開始研究官方的Demo代碼,終於發了這一塊,竟然需要處理Cookie策略,直接看代碼吧:

 

   public static class SameSiteHandlingExtensions
    {
        public static IServiceCollection AddSameSiteCookiePolicy(this IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
                options.OnAppendCookie = cookieContext => 
                    CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
                options.OnDeleteCookie = cookieContext => 
                    CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
            });

            return services;
        }
        
        private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
        {
            if (options.SameSite == SameSiteMode.None)
            {
                var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
                if (DisallowsSameSiteNone(userAgent))
                {
                    // For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)
                    options.SameSite = SameSiteMode.Unspecified;
                }
            }
        }

        private static bool DisallowsSameSiteNone(string userAgent)
        {
            // Cover all iOS based browsers here. This includes:
            // - Safari on iOS 12 for iPhone, iPod Touch, iPad
            // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
            // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
            // All of which are broken by SameSite=None, because they use the iOS networking stack
            if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12"))
            {
                return true;
            }

            // Cover Mac OS X based browsers that use the Mac OS networking stack. This includes:
            // - Safari on Mac OS X.
            // This does not include:
            // - Chrome on Mac OS X
            // Because they do not use the Mac OS networking stack.
            if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") && 
                userAgent.Contains("Version/") && userAgent.Contains("Safari"))
            {
                return true;
            }

            // Cover Chrome 50-69, because some versions are broken by SameSite=None, 
            // and none in this range require it.
            // Note: this covers some pre-Chromium Edge versions, 
            // but pre-Chromium Edge does not require SameSite=None.
            if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
            {
                return true;
            }

            return false;
        }
    }

 

 

 

然后把這個服務注冊:

 

 

 

 

最后中間件配置下Cookie策略:

 

 

 

有一個小伙伴說,只配置Cookie中間件即可,你也可以試試再。

 

2、無效Token,訪問無權限接口,異常

 

 

谷歌到了官方的 Issue,大家討論了很多,隨便找了一個:https://github.com/IdentityServer/IdentityServer4/issues/1627

簡單來說,主要是因為傳遞了一個無效的Token來訪問我們的資源服務器,導致中間件管道內異常,但是不影響正常使用,配置下,對token做下校驗即可,比如這樣的:

 

 

具體的可以查看我的代碼。

 

五、配置HTTPS

 在我的微信公眾號文章里:

https://mp.weixin.qq.com/s/GQXah1rq6qEMqcgAfWNkIw

 

 

六、下一步 2020

 

今年開始,一切都是新的,第一個閉環已經完成了,當然還有很多需要優化,比如單點登錄,DDD和Blog項目也遷移到Ids4上來,那下一個就開始了 —— CI/CD DevOps 我來了。

 

https://github.com/anjoy8/Blog.IdentityServer(授權)

https://github.com/anjoy8/Blog.Admin(客戶端)

https://github.com/anjoy8/Blog.Core(資源服務器)


免責聲明!

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



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