IdentityServer4 + SignalR Core +RabbitMQ 構建web即時通信html
.net core 2.1已經正式發佈了,signalr core1.0隨之發佈,是時候寫個demo了,這裏帶你們複習了下知識鏈,構建一個web即時聊天室,整個應用構建思路以下:
1.使用IdentityServer4做爲獨立的用戶中心與認證中心,採用password受權模式給客戶端提供token,
2.使用RabbitMQ做爲消息處理器,客戶端發送消息到服務端,服務器並不直接響應該消息,而是發送到消息隊列,再由消息處理器獲取消息併發送到客戶端,提升服務端的處理能力,
3.數據庫使用postgresql,原本準備使用mysql的,不過截止發稿時,EF Core2.1發佈後,mysql的使用Code First存在bug還未解決,
4.使用Docker構建RabbitMQ,postgresql應用,前端
5. 先後端分離。mysql
地址:https://github.com/280780363/signalrdemo.gitgit
Docker構建基礎應用RabbitMQ,postgresql
環境:虛擬機centos 7.0,docker
xshell鏈接到centos。
1,啓動RabbitMQ容器,官方鏡像地址,設置默認用戶admin,密碼123123,具體環境變量這些的設置能夠參考官方文檔: docker run -d --hostname myrabbit --name myrabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123123 -p 15672:15672 -p 5672:5672 -p 25672:25672 -p 61613:61613 -p 1883:1883 --restart=always rabbitmq:management
2.啓動postgresql,官方鏡像地址,設置默認用戶gucao,密碼123123,這裏啓動時設置的用戶是屬於超級管理員,掛載數據卷~/docker/postgresql/pgdata目錄做爲數據存儲目錄,--privileged設置容器擁有root權限進行文件讀寫: docker run --restart=always --privileged --name mypostgresql -e POSTGRES_PASSWORD=123123 -e POSTGRES_USER=gucao -v ~/docker/postgresql/pgdata:/var/lib/postgresql/data/ -d -p 5432:5432 postgres
成功啓動後: github
端口號都映射爲默認端口。psotgresql默認端口號5432,RabbitMQ用的到端口號比較多,15672是ui管理的端口號。個人虛擬機IP是192.168.1.107。瀏覽器打開地址:192.168.1.107:15672:web
能看到這個登陸頁面就說明一切ok了。輸入容器啓動時設置的用戶名密碼。登陸後能夠查看當前的一些隊列信息。sql
使用Navicat鏈接數據庫,也沒有問題:docker
就這麼簡單的2個命令就啓動了2個應用,若是本身下載安裝包來安裝,那真是夠折騰人的,還得考慮各類各樣的環境,不得不說docker真是一個偉大的工具。shell
IdentityServer4 用戶中心數據庫
關於IdentityServer4的具體各類使用這裏不會贅述,你們能夠多參考如下資料:
官方文檔
曉晨的博客
咱們這裏集成AspNetCore Identity提供用戶管理,客戶端(client),資源(ApiResource,IdentityResource)等配置資料都使用數據庫存儲。
須要用到的庫:
1.IdentityServer4;
2.IdentityServer4.AspNetIdentity ,IdentityServer4集成AspNetCore Identity用到的庫;
3.IdentityServer4.EntityFramework,IdentityServer4使用EF做爲數據存儲用到的庫;
4.Npgsql.EntityFrameworkCore.PostgreSQL,postgresql ef驅動庫;
5.Microsoft.EntityFrameworkCore.Tools,Ef Code First工具庫。
好吧,囉嗦一點,
1.建立空的.net core web項目 Demo.Identity,nuget安裝以上用到的庫;
2.建立appsettings.json配置文件,增長數據庫鏈接配置,文件名不能錯,ConnectionStrings不能錯,這是默認的約定
{ "ConnectionStrings": { "chat": "server=192.168.1.107;user id=gucao;password=123123;persistsecurityinfo=True;database=signalrdemo;" } }
3.增長Data文件夾,存放用戶實體,DbContext,種子數據文件類,這裏咱們使用guid做爲主鍵,這裏主要是AspNetCore Identity的類
DemoUser繼承自IdentityUser<Guid>,增長一個頭像屬性
public class DemoUser : IdentityUser<Guid> { public string Avatar { get; set; } }
由於默認是string類型的主鍵,要更改主鍵類型,須要同時建一個Role類,也設置爲guid主鍵,DemoRole:
public class DemoRole : IdentityRole<Guid> { }
DemoDbContext
public class DemoDbContext : IdentityDbContext<DemoUser, DemoRole, Guid> { public DemoDbContext(DbContextOptions<DemoDbContext> options) : base(options) { } }
SeedData就用來提供基本的數據了,這裏先設置3個用戶,要聊天總不能一我的聊得開心是吧
public static List<DemoUser> Users() { return new List<DemoUser>{ new DemoUser { UserName = "laowang", Email = "520@qq.com", Id = Guid.NewGuid(), EmailConfirmed = true, TwoFactorEnabled = false, Avatar = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1528131041794&di=78ae71a3573dc86bc010e301005fea53&imgtype=0&src=http%3A%2F%2Fpic2.orsoon.com%2F2017%2F0309%2F20170309032925886.png" }, new DemoUser { UserName = "zhangsan", Email = "521@qq.com", Id = Guid.NewGuid(), EmailConfirmed = true, TwoFactorEnabled = false, Avatar = "http://pic20.photophoto.cn/20110804/0010023712739303_b.jpg" }, new DemoUser { UserName = "lisi", Email = "521@qq.com", Id = Guid.NewGuid(), EmailConfirmed = true, TwoFactorEnabled = false, Avatar = "http://p1.qzone.la/upload/0/14vy5x96.jpg" } }; }
4.好了 下面開始配置StartUp中的服務,這裏我就直接貼代碼了
public void ConfigureServices(IServiceCollection services) { // 配置AspNetCore Identity 的DbContext服務 services.AddDbContext<DemoDbContext>(r => { r.UseNpgsql(configuration.GetConnectionString("chat"), options => { // 配置遷移時程序集 options.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); }); }); // 配置AspNetCore Identity服務用戶密碼的驗證規則 services.AddIdentity<DemoUser, DemoRole>(options => { options.Password.RequireDigit = false; options.Password.RequiredLength = 6; options.Password.RequireLowercase = false; options.Password.RequireUppercase = false; options.Password.RequireNonAlphanumeric = false; }) // 告訴AspNetCore Identity 使用DemoDbContext爲數據庫上下文 .AddEntityFrameworkStores<DemoDbContext>() .AddDefaultTokenProviders(); // 配置ids4服務 services.AddIdentityServer() .AddDeveloperSigningCredential() // ids4使用AspNetCore Identity爲用戶認證 .AddAspNetIdentity<DemoUser>() // 使用數據庫來存儲客戶端Clients ApiResource IdentityResource .AddConfigurationStore(options => { options.ConfigureDbContext = builder => { builder.UseNpgsql(configuration.GetConnectionString("chat"), sql => { sql.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); }); }; }) // 使用數據庫存儲受權操做相關操做,數據庫表PersistedGrants .AddOperationalStore(options => { options.ConfigureDbContext = builder => { builder.UseNpgsql(configuration.GetConnectionString("chat"), sql => { sql.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); }); }; }) // ids4使用自定義的用戶檔案服務 .Services.AddTransient<IProfileService, ProfileService>(); // 配置跨域,容許全部 services.AddCors(r => { r.AddPolicy("all", policy => { policy .AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials() ; }); }); }
這裏有一句Services.AddTransient<IProfileService, ProfileService>(),什麼意思呢?我但願在前端經過請求token時,token中自帶有用戶基本信息:用戶名,頭像等等,經過這個類配置ids4發佈token時帶上這些用戶信息;
public class ProfileService : IProfileService { UserManager<DemoUser> userManager; // 注入AspNetCore Identity的用戶管理類 public ProfileService(UserManager<DemoUser> userManager) { this.userManager = userManager; } public async Task GetProfileDataAsync(ProfileDataRequestContext context) { var claims = context.Subject.Claims.ToList(); // sub屬性就是用戶id var userId = claims.First(r => r.Type == "sub"); // 查找用戶 var user = await userManager.FindByIdAsync(userId.Value); claims.Add(new System.Security.Claims.Claim("username", user.UserName)); claims.Add(new System.Security.Claims.Claim("email", user.Email)); claims.Add(new System.Security.Claims.Claim("avatar", user.Avatar)); // 這裏是設置token包含的用戶屬性claim context.IssuedClaims = claims; } public async Task IsActiveAsync(IsActiveContext context) { context.IsActive = true; await Task.CompletedTask; } }
Configure
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseCors("all"); app.UseIdentityServer(); }
5.能夠開始生成遷移代碼了,這裏有3個DbContext類須要生成遷移:DemoDbContext,ConfiguraionDbContext(ids4 配置數據上下文),PersistedGrantDbContext(ids4受權操做數據上下文)
Add-Migration init -Context DemoDbContext -OutputDir Migrations/IdentityDbMigrations
Add-Migration init -Context ConfigurationDbContext -OutputDir Migrations/ConfigurationDbMigrations
Add-Migration init -Context PersistedGrantDbContext -OutputDir Migrations/PersistedGrantDbMigrations
好了,篇幅有點長了,先到這。