IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯


前言

.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. 前后端分离。

地址:https://github.com/280780363/signalrdemo.git


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
成功启动后:

端口号都映射为默认端口。psotgresql默认端口号5432,RabbitMQ用的到端口号比较多,15672是ui管理的端口号。我的虚拟机IP是192.168.1.107。浏览器打开地址:192.168.1.107:15672:

能看到这个登录页面就说明一切ok了。输入容器启动时设置的用户名密码。登录后可以查看当前的一些队列信息。

使用Navicat连接数据库,也没有问题:

就这么简单的2个命令就启动了2个应用,如果自己下载安装包来安装,那真是够折腾人的,还得考虑各种各样的环境,不得不说docker真是一个伟大的工具。


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 = ;
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

好了,篇幅有点长了,先到这。

IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(一)的更多相关文章

  1. IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(三)

    IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(三) 后台服务用户与认证 新建一个空的.net core web项目Demo.Chat,端口配置为 ...

  2. IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(二)

    IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(二) IdentityServer4 用户中心生成数据库 上文已经创建了所有的数据库上下文迁移代码 ...

  3. 一套简单的web即时通讯——第一版

    前言 我们之前已经实现了 WebSocket+Java 私聊.群聊实例,后面我们模仿layer弹窗,封装了一个自己的web弹窗 自定义web弹窗/层:简易风格的msg与可拖放的dialog,生成博客园 ...

  4. web即时通讯2--基于Spring websocket达到web聊天室

    如本文所用,Spring4和websocket要构建web聊天室,根据框架SpringMVC+Spring+Hibernate的Maven项目,后台使用spring websocket进行消息转发和聊 ...

  5. 为什么 web 开发人员需要迁移到. NET Core, 并使用 ASP.NET Core MVC 构建 web 和 webservice/API

    2018 .NET开发者调查报告: .NET Core 是怎么样的状态,这里我们看到了还有非常多的.net开发人员还在观望,本文给大家一个建议.这仅代表我的个人意见, 我有充分的理由推荐.net 程序 ...

  6. .Net core 3.0 SignalR+Vue 实现简单的即时通讯/聊天IM (无jq依赖)

    .Net core 中的SignalR JavaScript客户端已经不需要依赖Jquery了 一.服务端 1.nuget安装 Microsoft.AspNetCore.SignalR 2.在star ...

  7. Mysql EF Core 快速构建 Web Api

    (1)首先创建一个.net core web api web项目; (2)因为我们使用的是ef连接mysql数据库,通过NuGet安装MySql.Data.EntityFrameworkCore,以来 ...

  8. 基于spring reactor3构建的即时通讯api。

    欢迎阅读Rmessage文档 技术栈 Rmessage是采用Reactor3,基于reactor-netty项目构建的实时消息推送api. 什么是Reactor3? Reactor 是一个用于JVM的 ...

  9. 一套简单的web即时通讯——第二版

    前言 接上一版,这一版的页面与功能都有所优化,具体如下: 1.优化登录拦截 2.登录后获取所有好友并区分显示在线.离线好友,好友上线.下线都有标记 3.将前后端交互的值改成用户id.显示值改成昵称ni ...

随机推荐

  1. duilib入门简明教程 -- 界面布局(9) (转)

    原文转自:http://www.cnblogs.com/Alberl/p/3343806.html     上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的 ...

  2. hdu 3074(线段树)

    Multiply game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  3. SDOI2017round1酱油记day0

    嗯... 现在是21:12...准备睡了. 睡前写下day0一天如何过的: 早上5点起床到教室早自习,迷迷糊糊的宣誓,背东西,英语听写: 都停课了为什么还要上早自习! 我!想!去!机!房! OI才是我 ...

  4. 手游LTV(用户终生价值)计算公式

    在承接APP推广项目中,手游价值变现最直接,核心是获取更多的充值,其中LTV(Lifetime-Value生命周期价值)是一个重要参考指标,可以理解为玩家在其生命周期内对游戏的平均贡献值,为什么要计算 ...

  5. webpack学习(一)安装和命令行、一次js/css的打包体验及不同版本错误

    一.前言 找了一个视频教程开始学习webpack,跟着视频学习,在自己的实际操作中发现,出现了很多问题.基本上都是因为版本的原因而导致,自己看的视频是基于webpack 1.x版,而自己现在早已是we ...

  6. Light oj 1044 - Palindrome Partitioning(区间dp)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1044 dp[i][j]表示i到j直接的最小回文区间个数,直接看代码 #include ...

  7. POJ 2411 Mondriaan's Dream [经典状态压缩dp]

    题意:略. 思路:这一题开始做的时候完全没有思路,便去看了别人的题解. 首先,对于这个题目解法想有一个初步的了解,请看这里:http://www.2cto.com/kf/201208/146894.h ...

  8. Maven错误:“No goals have been specified for this build...”问题解决

    如图出现如下错误: 解决方法如下: 1.(未测试)在pom.xml添加如下配置: <build> <defaultGoal>compile</defaultGoal> ...

  9. golang实现dns域名解析(二)

    上一节已经讲了如何构造dns请求包的情况,这一节接着上一节的情况,谈谈dns查询报文中的问题部分.问题部分中每个问题的格式如下: 查询名是要查找的名字,它是一个或者多个标识符的序列.每个标识符以首字母 ...

  10. html使用示例

    select标签 <select name="Area" id="Area" class="sel"> <option v ...