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. 中间件 ...
随机推荐
- Matplotlib 多个图形
章节 Matplotlib 安装 Matplotlib 入门 Matplotlib 基本概念 Matplotlib 图形绘制 Matplotlib 多个图形 Matplotlib 其他类型图形 Mat ...
- ArrayList和LinkedList、Vector的优缺点?
一般在面试中可能会被问到ArrayList.LinkedList.Vector三者相关的区别! 一般来说我想大概都会回答如下的这些: ArrayList底层是数组结构,查询快,增删慢,线程不安全,效率 ...
- Python Sphinx使用踩坑记录
描述 使用 pip 安装sphinx后,按照教程建立了一个新的py文件,如下 # run.py def run(name): """ this is how we run ...
- 007-PHP变量和函数相互转换
<?php function write($text) //定义function write()函数 { print($text); //打印字符串 } function writeBold($ ...
- css3的伪(伪类和伪元素)大合集
本文讲css3的伪,不是讲它有多虚伪,而是说它的伪元素样式.不得不说以前虽知html伪元素,但很少用,后得知借助css3伪元素可以发挥极大的便利.故总结css3的伪如下: CSS中存在一些比较特殊的属 ...
- 吴裕雄--天生自然java开发常用类库学习笔记:观察者设计模式
import java.util.* ; class House extends Observable{ // 表示房子可以被观察 private float price ;// 价钱 public ...
- POJ 2287 田忌赛马
Tian Ji -- The Horse Racing Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 17699 Acc ...
- JavaScript中的apply()方法和call()
apply()和call()的真正用武之地是能够扩充函数赖以运行的作用域 两个函数的第一个参数是都是,要执行语句的作业域,即this 区别是 apply后面只能传一个大参数,call后面参数只能一 ...
- js使用new操作符创建对象
转 在编写js代码时,我们有时会需要使用函数来模拟java中的类,并用它来产生对象,在定义了一个构造函数之后我们需要使用new操作符来调用调用函数才能得到我们想要的对象.例如: function Co ...
- bzoj 1912: [Apio2010]patrol 巡逻
呵呵呵呵呵呵,自己画图,大概半个小时,觉的连上边会成环(是不是该交仙人掌了??)然后求环不重合部分最大就好了, 结果写了一坨DP,最后写不下去了,再次扒了题解. 发现我真的是个sb. k==1,直接是 ...