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. 中间件 ...
随机推荐
- vs2015中安装cplex攻略以及解决丢失cplex.dll问题
转:http://blog.sina.com.cn/s/blog_61f0374801014swp.html 按:相信配置过CPLEX的人大多有过痛苦而难忘的经历,本人亦不例外,纠结挣扎了一个下午加一 ...
- 有关WordPress的Rss导入指南
我是用cublog转过来.有一个软件博客备份软件(blog_backup)可以备份那个的blog.我用他备份后导出成rss2的文件.但我导入了很多次不成功.后来发现,原来blog_backup导出的格 ...
- windowsService 程序
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- 87)PHP,PDO的预编译技术
(1) 比如以下的语句: insert into biao1 values(‘李宁’,‘’): insert into biao1 values(‘安踏’,‘’): insert into biao1 ...
- JAVA虚拟机:Java技术体系讲解(一)
按照Java系统的功能划分为: 一.Java语言,即使用Java编程语言进行软件开发. 二.开发过程中使用的工具和API(API(Application Programming Interface,应 ...
- HiBench成长笔记——(11) 分析源码run.sh
#!/bin/bash # Licensed to the Apache Software Foundation (ASF) under one or more # contributor licen ...
- other#nginx配置
#user nobody; worker_processes ; #error_log logs/error.log; #error_log logs/error.log notice; #error ...
- Spring的JDBC的使用(配置和CRUD)
导包: Spring的JDBC模板的使用 一.默认连接池 创建数据库 create database spring4; use spring4; create table account(id int ...
- SpringBoot配置介绍
SpringBoot配置介绍 SpringBoot如何进行配置 在SpringBoot中默认使用Servlet3.0可以没有web.xml,没有任何的xml,我们想要做一些自定义配置,比u数据库相关信 ...
- ACM-吴奶奶买鱼
题目描述:吴奶奶买鱼 吴奶奶有个可爱的外孙女——琪琪,她很喜欢小动物,尤其喜欢养鱼.为了让小孙女养到漂亮的小鱼,吴奶奶一大早就到花鸟鱼虫市场买鱼.这个市场可真大,里面有各种各样的宠物,就连宠物鱼都 ...