ASP.NET Identity实现分布式Session,Docker+Nginx+Redis+ASP.NET CORE Identity
零、背景介绍
在学习ASP.NET CORE开发的过程中,身份认证是必须考虑的一项必要的组件。ASP.NET CORE Identity是由微软官方开发的一整套身份认证组件,兼具完整性和自由度。Docker作为目前虚拟化的主流解决方案,可以很快捷地实现应用的打包和部署。Nginx作为反向代理,结合Docker多环境部署,可以实现负载均衡功能。而在分布式环境下,Session的共享,特别是登录状态的共享是难以逾越的一个“小”问题。
然而,这个“小”问题,却让我花费了大量的时间搞清楚了相互之间的协作关系,并成功实现了Docker+Nginx+Redis多种组件相结合的解决方案。
环境:ASP.NET Core 2.0
一、ASP.NET CORE Identity
为了实现Session共享,需要在Cookie中存储Session的ID信息以及用户信息,从而实现在多个应用之间的信息共享。有关ASP.NET CORE Identity的介绍,这里不在赘述。
ASP.NET CORE Identity主要包括UserManager和SignInManager两个主要的管理类,从名称可以看出来SignInManager实现的是登陆的管理,因为涉及到登录状态以及登录用户信息的共享,所以我们需要实现自定义的SignInManager类,重写其中最为重要的登录和登出方法。
public override Task<SignInResult> PasswordSignInAsync(ApplicationUser user, string password, bool isPersistent, bool lockoutOnFailure)
{
return base.PasswordSignInAsync(user, password, isPersistent, lockoutOnFailure)
.ContinueWith<SignInResult>(task =>
{
if (task.Result == SignInResult.Success)
{
LoginSucceeded(user);
} return task.Result;
});
} public override Task<SignInResult> TwoFactorAuthenticatorSignInAsync(string code, bool isPersistent, bool rememberClient)
{
ApplicationUser au = this.GetTwoFactorAuthenticationUserAsync().Result;
return base.TwoFactorAuthenticatorSignInAsync(code, isPersistent, rememberClient)
.ContinueWith<SignInResult>(task =>
{
if (task.Result == SignInResult.Success && au != null)
{
LoginSucceeded(au);
} return task.Result;
});
} public override Task SignOutAsync()
{
return base.SignOutAsync()
.ContinueWith(task =>
{
LogoutSucceeded(Context.Request.Cookies["sessionId"]);
}); ;
} public override bool IsSignedIn(ClaimsPrincipal principal)
{
if (!Context.User.Identity.IsAuthenticated)
{
if (Context.Request.Cookies.ContainsKey("sessionId"))
{
string userInfor = Context.Session.GetString(Context.Request.Cookies["sessionId"]);
if (!string.IsNullOrEmpty(userInfor))
{
ApplicationUser user = JsonConvert.DeserializeObject<ApplicationUser>(userInfor);
if (user != null)
{
principal = Context.User = this.ClaimsFactory.CreateAsync(user).Result;
}
}
}
} var flag = base.IsSignedIn(principal); return flag;
} private void LoginSucceeded(ApplicationUser user)
{
try
{
string sessionId = Guid.NewGuid().ToString();
string userInfor = JsonConvert.SerializeObject(user);
Context.Session.SetString(sessionId, userInfor);
Context.Response.Cookies.Delete("sessionId");
Context.Response.Cookies.Append("sessionId", sessionId);
}
catch (Exception xcp)
{
MessageQueue.Enqueue(MessageFactory.CreateMessage(xcp));
}
} private void LogoutSucceeded(string sessionId)
{
try
{
if (!string.IsNullOrEmpty(sessionId))
{
Context.Session.Remove(sessionId);
}
}
catch (Exception xcp)
{
MessageQueue.Enqueue(MessageFactory.CreateMessage(xcp));
}
}
MySignInManager
重写之后,需要在Startup.cs代码ConfigureServices方法中注册使用。
services.AddIdentity<ApplicationUser, IdentityRole>(o =>
{
o.Password.RequireNonAlphanumeric = false;
})
.AddEntityFrameworkStores<MyDbContext>()
.AddSignInManager<MySignInManager>()
.AddDefaultTokenProviders();
二、Docker
在实现自定义Identiy中的SignInManager类以后,将网站打包为Docker镜像(Image),然后根据需要运行多个容器(Container),这些容器的功能是相同的,其实是多个网站实例,跑在不同的端口上面,相当于实现了分布式部署。比如,运行三个容器的命令如下,分别跑在5000,5001和5002端口。
docker run --name webappdstr_0 -d -p : -v /etc/localtime:/etc/localtime webapp:1.0
docker run --name webappdstr_1 -d -p : -v /etc/localtime:/etc/localtime webapp:1.0
docker run --name webappdstr_2 -d -p : -v /etc/localtime:/etc/localtime webapp:1.0
三、Nginx
在完成应用部署后,通过修改Nginx配置,实现负载均衡功能。主要配置如下:
# WebAppDistributed
server{
listen ssl;
server_name www.webapp.com; ssl_certificate ../cert/ssl.crt;
ssl_certificate_key ../cert/ssl.key; location / {
proxy_pass http://webappserverd/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
} upstream webappserverd{
server localhost:;
server localhost:;
server localhost:;
}
Nginx config
以上配置5000,5001和5002三个应用,即对应于Docker部署的三个网站应用。
四、Redis
Redis主要是实现Session的共享,通过Microsoft.Extensions.Caching.Redis.Core组件(通过Nuget获取),在Startup.cs代码ConfigureServices方法中添加Redis中间件服务。
// Redis
services.AddDistributedRedisCache(option =>
{
//redis 数据库连接字符串
option.Configuration = Configuration.GetConnectionString("RedisConnection");
//redis 实例名
option.InstanceName = "master";
});
Redis的地址获取的是appsettings.json配置中的配置项。
{
"ConnectionStrings": {
...,
"RedisConnection": "192.168.1.16:6379"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
五、重点难点
主要是总结下碰到的各种坑以及解决方案。
1、Session共享的需要DataProtection以及相关的配置支持
ASP.NET CORE对Session进行了加密,为了能够在多个分布式应用中实现共享,则需要使用相同的加密Key。实现共享的方式有多种,这里采用自定义XmlRepository来实现。
public class CustomXmlRepository : IXmlRepository
{
private readonly string keyContent = @""; //使用前,插入key内容 public virtual IReadOnlyCollection<XElement> GetAllElements()
{
return GetAllElementsCore().ToList().AsReadOnly();
} private IEnumerable<XElement> GetAllElementsCore()
{
yield return XElement.Parse(keyContent);
}
public virtual void StoreElement(XElement element, string friendlyName)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
StoreElementCore(element, friendlyName);
} private void StoreElementCore(XElement element, string filename)
{
}
}
CustomXmlRepository
之后,在Startup.cs中启用DataProtection中间件,并进行配置。
// Set data protection.
services.AddDataProtection(configure =>
{
configure.ApplicationDiscriminator = "WebApplication";
})
.SetApplicationName("WebApplication")
.AddKeyManagementOptions(options =>
{
//配置自定义XmlRepository
options.XmlRepository = new CustomXmlRepository();
})
.ProtectKeysWithCertificate(new System.Security.Cryptography.X509Certificates.X509Certificate2("webapp.crt"));
Startup.cs
ASP.NET Identity实现分布式Session,Docker+Nginx+Redis+ASP.NET CORE Identity的更多相关文章
- ASP.NET WebApi 基于分布式Session方式实现Token签名认证
一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...
- ASP.NET WebApi 基于分布式Session方式实现Token签名认证(发布版)
一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...
- Centos8 Docker+Nginx部署Asp.Net Core Nginx正向代理与反向代理 负载均衡实现无状态更新
首先了解Nginx 相关介绍(正向代理和反向代理区别) 所谓代理就是一个代表.一个渠道: 此时就涉及到两个角色,一个是被代理角色,一个是目标角色,被代理角色通过这个代理访问目标角色完成一些任务的过程称 ...
- asp.netcore 自动挡Docker Nginx Redis(滴滴滴,自动挡)
前言 上一章介绍了Docker通过多条命令创建启动运行Docker容器,由此可见这样一个个去创建单独的容器也是相当麻烦的,比如要在某个复杂项目中用DB.缓存.消息等等,这样我们还要去一个个再创建,为此 ...
- Spring Boot 分布式Session状态保存Redis
在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而打到另外一台服务器的时候,session丢失. 常规的解决方 ...
- (38)Spring Boot分布式Session状态保存Redis【从零开始学Spring Boot】
[本文章是否对你有用以及是否有好的建议,请留言] 在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而访问到另外 ...
- docker+nginx+redis部署前后端分离项目!!!
介绍本文用的经典的前后端分离开源项目.项目的拉取这些在另一篇博客!!! 其中所需要的前后端打包本篇就不做操作了!!不明白的去看另一篇博客!!! 地址:http://www.cnblogs.com/ps ...
- ASP.NET Core中间件实现分布式 Session
1. ASP.NET Core中间件详解 1.1. 中间件原理 1.1.1. 什么是中间件 1.1.2. 中间件执行过程 1.1.3. 中间件的配置 1.2. 依赖注入中间件 1.3. Cookies ...
- ASP.NET Core中间件实现分布式 Session(转载)
ASP.NET Core中间件实现分布式 Session 1. ASP.NET Core中间件详解 1.1. 中间件原理 1.1.1. 什么是中间件 1.1.2. 中间件执行过程 1.1.3. 中间件 ...
随机推荐
- 「NOI2015」荷马史诗
传送门 Luogu 解题思路 \(k\) 叉 \(\text{Huffman}\) 树板子题,至于最长串最短,只要同样权值的优先考虑深度小的就好了. 细节注意事项 咕咕咕 参考代码 #include ...
- Vue.js事件处理
Vue.js事件处理 1.v-on指令 用法如下:使用v-on:指令指定其执行的具体内容或者方法名即可. <button v-on:click='num++'>giao</butto ...
- ubuntu 系统分配固定 ip--
由于Ubuntu重启之后,ip很容易改变,可以用以下方式固定ip地址 1.设置ip地址 vi /etc/network/interface # The loopback network interfa ...
- Echarts 折线图y轴标签值过长 显示
参考: https://blog.csdn.net/dandelion_drq/article/details/79270597 改变Y轴单位:https://www.cnblogs.com/cons ...
- L2-002. 链表去重(模拟)
题意: 给定一个带整数键值的单链表L,本题要求你编写程序,删除那些键值的绝对值有重复的结点.即对任意键值K,只有键值或其绝对值等于K的第一个结点可以被保留.同时,所有被删除的结点必须被保存在另外一个链 ...
- Thinkcmf任意漏洞包含漏洞分析复现
简介 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建.ThinkCMF提出灵活的应用机制,框架自身提供基础的管理功能,而开发者可以根据自身的 ...
- 富文本API
这个笔记来自网络资料的总结 简书大佬三省吾身_9862 tuobaye个人博客 富文本有相关3个API和一个新属性 var selection = window.getSelection(); var ...
- springboot 中单机 redis 实现分布式锁
在微服务中经常需要使用分布式锁,来执行一些任务.例如定期删除过期数据,在多个服务中只需要一个去执行即可. 以下说明非严格意义的分布式锁,因为 redis 实现严格意义的分布式锁还是比较复杂的,对于日常 ...
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-pause
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
- H5页面,华为手机打开不加载JS的问题
今天在做H5页面放在其他手机上面都可以刷出列表,但是就是放在华为手机上面刷不出来,怎么想都想不通,后面主管说华为手机的浏览器是严格遵守H5什么鬼东西的,然后其他浏览器做到比较好的,如果有报错就帮我们解 ...