1. 程式人生 > >解析微軟微服務架構eShopOnContainers(二)

解析微軟微服務架構eShopOnContainers(二)

上一篇,眾所周知一個網站的使用者登入是非常重要,一站式的登入(SSO)也成了大家討論的熱點。微軟在這個Demo中,把登入單獨拉了出來,形成了一個Service,使用者的註冊、登入、找回密碼等都在其中進行。

這套service是基於IdentityServer4開發的, 它是一套基於 .Net Core的OAuth2和OpenID框架,這套框架目前已經很完善了,我們可以把它使用到任何專案中。

我們先看下目錄結構:

從目錄結構可以看出它是一套MVC架構的網站,我們可以單獨進行執行和除錯,當然,我們也可以把它放進自己的專案中。

從.Net Core開始,我們看程式碼的順序從Web.config轉到了Program.cs中,我們來看下IdentityService的Program:

複製程式碼
public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseHealthChecks("/hc") //多了一個健康檢查
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
}
複製程式碼 跟普通的.Net Core專案類似,不過多了一個UseHealthChecks,從名字上也能看出,這是一個對專案健康的檢查,有興趣的話到時候我們另外開篇介紹。看完Program我們看下Startup

在初始化的時候,我們看到的程式碼基本與系統相同,多了一個加入builder.AddUserSecrets(), 這是一個使用者資訊加密方法,避免我們在提交共享專案的時候,會把自己一些重要資訊洩露,有興趣的朋友可以看下Secret Manager Tools

在ConfigureServices中,我們看到有一段程式碼:

services.AddDataProtection(opts =>
{
    opts.ApplicationDiscriminator = "eshop.identity
"; });

這段程式碼意思是加了一個唯一標示符給應用程式,這在叢集環境中是非常必要的,我們可以通過這個唯一標識來判斷是否是同一個應用(我們的同一應用可能會分佈在不同server上),具體可以看園內大神的專題:Asp.Net Core 資料保護

Going Down:

複製程式碼
services.AddHealthChecks(checks =>
{
    var minutes = 1;
    if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
    {
        minutes = minutesParsed;
    }
    checks.AddSqlCheck("Identity_Db", Configuration.GetConnectionString("DefaultConnection"), TimeSpan.FromMinutes(minutes));
});
複製程式碼

又是Health檢查,這次檢查了與資料庫連線的狀態。

複製程式碼
services.AddTransient<IEmailSender, AuthMessageSender>();   //郵件傳送服務
services.AddTransient<ISmsSender, AuthMessageSender>();     //簡訊傳送服務
services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>();    //EF 登入服務
services.AddTransient<IRedirectService, RedirectService>(); //重定向服務

//callbacks urls from config:
Dictionary<string, string> clientUrls = new Dictionary<string, string>();
clientUrls.Add("Mvc", Configuration.GetValue<string>("MvcClient"));
clientUrls.Add("Spa", Configuration.GetValue<string>("SpaClient"));
clientUrls.Add("Xamarin", Configuration.GetValue<string>("XamarinCallback"));

// Adds IdentityServer
services.AddIdentityServer(x => x.IssuerUri = "null")
    .AddSigningCredential(Certificate.Get())
    .AddInMemoryApiResources(Config.GetApis())
    .AddInMemoryIdentityResources(Config.GetResources())
    .AddInMemoryClients(Config.GetClients(clientUrls))
    .AddAspNetIdentity<ApplicationUser>()
    .Services.AddTransient<IProfileService, ProfileService>();
複製程式碼

為identityserver4 進行相關配置。Startup中的Configure沒什麼特別的。

簡單的看了下Identity專案,好像就是教你怎麼使用IdentityServer4,So,你可以在部落格園中找到好多相關資料,這裡就不重複介紹了。

在這個service中,發現了很多沒有用到的類和屬性,估計是為了以後擴充套件用的吧。

例如:

複製程式碼
var user = await _loginService.FindByUsername(model.Email);
if (await _loginService.ValidateCredentials(user, model.Password))
{
    AuthenticationProperties props = null;
    if (model.RememberMe)
    {
        props = new AuthenticationProperties
        {
            IsPersistent = true,
            ExpiresUtc = DateTimeOffset.UtcNow.AddYears(10)
        };
    };

    await _loginService.SignIn(user);
    // make sure the returnUrl is still valid, and if yes - redirect back to authorize endpoint
    if (_interaction.IsValidReturnUrl(model.ReturnUrl))
    {
        return Redirect(model.ReturnUrl);
    }

    return Redirect("~/");
}
複製程式碼

這是AccountController使用者登入的一段程式碼,其中的props屬性進行了設定,但是在後面沒有使用到,因為是為以後支援持續化登入做的準備吧。還有在Services目錄中的ProfileService,在專案中也沒有進行呼叫,相信在後面的版本中會加上去的。

執行部署

瞭解了專案後,我們再來進行執行和部署。

首先,我們需要一臺MSSQL Server,因為我們需要儲存使用者資料,建議用SQL 2008 update3以上,為何用update3以上後面會說,當然你也可以使用其他型別的資料庫,比如MySql,Sqlite等。

其次,把Identity專案設定為啟動專案,試著Ctrl+F5執行,看看是否執行成功。

afdd4fc5-de60-4ac6-ba1e-32bf2a776271

當你能在瀏覽器看到這個頁面的時候,說明程式執行正常,配置也正確,接下來看下如何在docker中執行。

1、右鍵專案-釋出,把專案編譯釋出到某個資料夾中。

2、開啟你的終端,如果是win10之前的系統,請開啟Docker Quickstart Terminal

我用的是win7,使用的是Quickstart終端,其他系統只要是使用linux container的都一樣,否則怎麼叫“build once, run anywhere”呢。

3、在終端上先cd到你的釋出目錄,如果不在同一個驅動器下的,使用 /(driver)/ 代替driver:,例如,我的專案釋出在D:\Projects\publish

    cd /d/projects/publish

在你的終端看到輸入處上一行有這個目錄的,說明你已經進入到這個目錄了,如:

image

4、用ls檢視下這個目錄,你會看到編譯後的檔案都在這裡(release),在資料夾中,你會看到dockerfile檔案,這個相當於docker的批處理檔案,我們看下內容,具體如何寫,可以看部落格園中其他大神的教程:

複製程式碼
FROM microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "Identity.API.dll"]
複製程式碼

5、在終端執行docker build命令,建立你的image(請注意最後的“.”,這個代表的當前目錄):

docker build -t identity:01 .

6、成功後,我們使用docker images 可以檢視,如果在list中有identity的話,說明我們建立成功了

7、run起來

docker run -p 8888:80 --name identity -d identity:01

imageimage

撒都沒有,撒情況!!!!

通過檢查,終於知道了原因,我們使用的docker-toolbox,所以它會藉助於VritualBox來建立一個linux執行環境,所以我們必須把虛擬機器中的埠對映到我的本機!

d01f9762-76dd-45a4-82f3-a79f54b40718

想著這下總歸可以了吧,誰知道。。。。。還是無法訪問,在quickstart中,我輸入了docker logs identity 看到如下日誌:

image

這什麼鬼,time out!!可我iis執行都是正常的啊,不存在資料庫連線不上的問題吧!這個問題足足困擾了我2天,晚上也睡不好,第3天早上,突然想到會不會linux容器的關係呢?之前google的都是錯誤資訊,所以撒都沒有搜出來,我改了下關鍵字 linux containers connection sqlserver,果不其然,在一個issue中發現了答案:

原來我們的sql2008沒有支援這種登入request,我們必須升級到update3才能解決這個問題,為了讓教程繼續,我購買了azure的1元試用,更換了connection後,我重新build和run,終於看到了熟悉的頁面:

image

寫在最後

在Identity Service中,我們看到了一些新的東西,比如secret manager tool,healthcheck等,雖說它是基於identityServer4搭建的,但至少它教會了我們如何使用identityServer4,而且我們完全可以單獨把它拉出來作為我們自己的user server,我也是第一次接觸IdentityServer4,以後大家可以一起學習討論下,感覺非常強大。最後我們學習瞭如何單獨搭建和部署identity service,並使其能夠在docker中正常執行。

PS:最近工作不是很忙,所以有些時間去研究這些,如果中途斷檔的話,還請大家見諒!