This project adds functionality on top of the asp.net core Identity package to enable immediate actions against users as admin. E.g: Immediate log-out or refresh-sign-in.
https://www.nuget.org/packages/Kaktos.UserImmediateActions/
PM> Install-Package Kaktos.UserImmediateActions -Version 2.0.1
To immediately remove/add a role or a claim from/to a user as an admin, you can first remove the roles you want using UserManager
and RoleManager
classes and then use the refresh-sign in functionality to
immediately update the user cookie. To sign out a user from their account you can use the sign-out functionality to sign out a user immediately from their account.
- Get it on NuGet
- Quick tutorial
- How to use IUserImmediateActionsService
- Services
- Extension methods
- How this package works
- To start, after using the
AddIdentity
and setting up the identity services, useAddUserImmediateActions
extension method to add all the default services to IoC container.
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders()
.AddUserImmediateActions();
- After registering the services, its now time for some Middlewares! use the
UseUserImmediateActions
middleware as shown below. make sure to use it between theUseAuthentication
andUseAuthorization
for correct behavior.
app.UseAuthentication();
app.UseUserImmediateActions();
app.UseAuthorization();
- Now that we registered all the services and Middlewares that we need (that was quick!) it's now time to use this package. The main service that you need to use
is
IUserImmediateActionsService
.
public class MyController : Controller
{
private readonly IUserImmediateActionsService _userImmediateActionsService;
public MyController(IUserImmediateActionsService userImmediateActionsService)
{
_userImmediateActionsService = userImmediateActionsService;
}
}
Now get an instance of IUserImmediateActionsService
from the IoC container using the constructor injection (or any other method you want), and then use it to perform your desired
action!
[HttpPost]
public async Task<IActionResult> EditUser(EditUser model)
{
if (ModelState.IsValid)
{
/*
First, update the user, then use the method below for user immediate cookie update AKA refresh-sign in.
*/
await _userImmediateActionsService.RefreshCookieAsync(model.UserId);
/*
If for any reason you want to sign a user out from their account, use the method below.
Also, it is recommended to update the user SecurityStamp too so we can ensure a sign-out on all devices,
to update the user SecurityStamp, use the second method below.
*/
await _userImmediateActionsService.SignOutAsync(model.UserId);
await _userManager.UpdateSecurityStampAsync(await _userManager.FindByIdAsync(model.UserId));
}
return View(model);
}
Highlight: Its recommended reading the documentation as it contains useful information about how this package works.
( This part makes more sense if you have read the services section first. )
In this service, there are two main methods SignOut
and RefreshCookie
, and also their Async version. Both of them will get an UserId as a parameter and will turn it into a
unique key before storing it using the main store service alongside some other information. In the Async methods the storing operation is done asynchronously (depends on the
provided implementation of IImmediateActionsStore
).
Warning:
Make sure to update user SecurityStamp using the UpdateSecurityStampAsync
method from UserManager
when calling the SignOut
or SingOutAsync
, to make sure the user will be
singed-out from their account on all their devices. if SecurityStamp is not updated, there is a possibility that the user will not be signed out on some devices.
This service is used internally to increase the testability of this package when we need date and time.
IImmediateActionsStore
service is all about storing data. in this package we have two types of storage, first type is IImmediateActionsStore
and we will call it the main
store service in this documentation. The main pro of this service is its performance, it can save and especially read data pretty fast. for this reason, this service will use some
sort of caching mechanism to store data. By default, this service will use
IMemoryCache
for storing data, but you can change it to use IDistributedCache
by using the AddDefaultDistributedImmediateActionStore
extension method.
IPermanentImmediateActionsStore
service is the second type of storage, and we will call it the permanent store service
in this documentation. The main pro of this service is that it can save data permanently. We can use this server to avoid losing data on each application restart because of the use
of caching services. Internally when the main store service
methods are called to store some data, the permanent store service methods are called to store the same data.
Warning:
By default there is no real implementation of permanent store service, the added implementation of this service is fake and does nothing. To register a real working
implementation of this service you need to use the AddPermanentImmediateActionsStore
and pass your implementation to it.
IUserActionStoreKeyGenerator
service is responsible for generating the unique keys that is used in the main store service.
IUserImmediateActionsService
service contains the methods that you will use. explained in the quick tutorial.
ICurrentUserWrapperService
service is used internally in this package. it is used when a user needs to be singed-out
or we need to refresh their cookie. By default, the implementation of this service uses UserManager
and SignInManager
provided by the asp.net core Identity package to achieve its goals. to use your own implementation use
AddCurrentUserWrapperService
extension method and pass your implementation to it.
Adds the default services to the IoC container. you can read more about the provided services in the services section.
services.AddMemoryCache();
services.AddSingleton<IDateTimeProvider, DateTimeProvider>();
services.TryAddSingleton<IPermanentImmediateActionsStore, FakePermanentImmediateActionsStore>();
services.TryAddTransient<IImmediateActionsStore, MemoryCacheImmediateActionsStore>();
services.TryAddSingleton<IUserActionStoreKeyGenerator, UserActionStoreKeyGenerator>();
services.TryAddTransient<IUserImmediateActionsService, UserImmediateActionsService>();
services.TryAddScoped(typeof(ICurrentUserWrapperService), typeof(IdentityCurrentUserWrapperService<>).MakeGenericType(builder.UserType));
Adds a permanent store service implementation.( Require inheritance from IPermanentImmediateActionsStore
)
public static IdentityBuilder AddPermanentImmediateActionsStore<TPermanentStore>(this IdentityBuilder builder) where TPermanentStore : class, IPermanentImmediateActionsStor
Adds the default implementation of main store service that uses IDistributedCache
.
public static IdentityBuilder AddDefaultDistributedImmediateActionStore(this IdentityBuilder builder)
Adds your implementation of main store service.( Require inheritance from IImmediateActionsStore
)
public static IdentityBuilder AddDistributedImmediateActionStore<TStore>(this IdentityBuilder builder) where TStore : class, IImmediateActionsStore
Adds your implementation for generating unique keys that are used in the main store service.( Require inheritance from IUserActionStoreKeyGenerator
)
public static IdentityBuilder AddUserActionStoreKeyGenerator<TGenerator>(this IdentityBuilder builder) where TGenerator : class, IUserActionStoreKeyGenerator
Adds your implementation of IUserImmediateActionsService
that contains the methods you will use!( Require inheritance from IUserImmediateActionsService
)
public static IdentityBuilder AddUserImmediateActionsService<TActionService>(this IdentityBuilder builder) where TActionService : class, IUserImmediateActionsService
Adds your implementation of ICurrentUserWrapperService
that contains the methods used to refresh and sign out a user
( this service is used internally in this package ). ( Require inheritance from ICurrentUserWrapperService
)
public static IdentityBuilder AddCurrentUserWrapperService<TUserWrapperService>(this IdentityBuilder builder) where TUserWrapperService : class, ICurrentUserWrapperService
( This part makes more sense if you have read the services section first. )
After calling one of the methods in IUserImmediateActionsService
, the given userId will be used to generate a unique key using
IUserActionStoreKeyGenerator
. After that an instance of ImmediateActionDataModel
that contains the generated key and some
other information will be stored in the main store (and possibly the permanent store if an implementation is provided),
then in the UserImmediateActionsMiddleware
we will check every user if they need to be signed-out or their cookie needs to be refreshed using the data given by main store service. It is worth mentioning that because of how this middleware is implemented and the usage of a caching service that usually stores data in the ram, there should be little to no performance penalty.
(The main bottleneck here is the read performance of the caching service used and we can't really benchmark it,
because the performance will vary based on the caching service you use, your latency to the caching server, and many other parameters. but as mentioned, generally, there should be little to
no performance penalty.)
If you like this project or you are using it in your application, please give it a star. Thanks!
این پکیج به سیستم asp.net core identity عملیات های sing-out و refresh-sign-in برای کاربران به صورت آنی توسط ادمین اضافه خواهد کرد.
https://www.nuget.org/packages/Kaktos.UserImmediateActions/
PM> Install-Package Kaktos.UserImmediateActions -Version 2.0.1
برای حذف کردن یک Role یا Claim به صورت آنی میتوان از refresh-signin استفاده کرد تا مقادیر آپدیت شده به صورت آنی در کوکی کاربر اعمال شوند. برای خارج کردن کاربر از حساب کاربری خود به صورت آنی، میتوان از sign-out استفاده کرد تا کاربر به صورت آنی از حساب کاربری خود خارج شود.
- توسط NuGet نصب کنید
- آموزش استفاده
- آموزش استفاده کامل از IUserImmediateActionsService
- سرویس ها
- اکستنشن متود ها
- اکستنشن متود AddUserImmediateActions
- اکستنشن متود AddPermanentImmediateActionsStore
- اکستنشن متود AddDefaultDistributedImmediateActionStore
- اکستنشن متود AddDistributedImmediateActionStore
- اکستنشن متود AddUserActionStoreKeyGenerator
- اکستنشن متود AddUserImmediateActionsService
- اکستنشن متود AddCurrentUserWrapperService
- نحوه کار این پکیج
- برای شروع بعد از استفاده از
AddIdentity
و موارد موردنیاز خود، از اکستنشن متودAddUserImmediateActions
استفاده بکنید تا تمامی سرویس های پیشفرض موردنیاز به سیستم Dependency injection اضافه بشوند.
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders()
.AddUserImmediateActions();
- بعد از اضافه کردن سرویس های مورد نیاز، نوبت به اضافه کردن Middleware میرسه! از
UseUserImmediateActions
به صورت زیر استفاده کنید. دقت داشته باشید کهUseUserImmediateActions
حتما بینUseAuthentication
وUseAuthorization
باشه تا به درستی کار بکنه.
app.UseAuthentication();
app.UseUserImmediateActions();
app.UseAuthorization();
- خوب الان که تمامی سرویس ها و Middleware های موردنیاز رو اضافه کردیم ( چه سریع تموم شد! ) نوبت به استفاده از این سرویس ها میرسه. سرویس اصلی که شما با اون سروکار خواهید داشت
سرویس
IUserImmediateActionsService
خواهد بود.
public class MyController : Controller
{
private readonly IUserImmediateActionsService _userImmediateActionsService;
public MyController(IUserImmediateActionsService userImmediateActionsService)
{
_userImmediateActionsService = userImmediateActionsService;
}
}
از طریق سازنده کلاس ( Constroctur ) یک نمونه از سرویس IUserImmediateActionsService
دریافت کنید و سپس از ان برای انجام عملیات موردنظر خود استفاده کنید!
[HttpPost]
public async Task<IActionResult> EditUser(EditUser model)
{
if (ModelState.IsValid)
{
/*
ابتدا کاربر را آپدیت کنید و سپس از متود زیر برای آپدیت آنی کاربر استفاده کنید
*/
await _userImmediateActionsService.RefreshCookieAsync(model.UserId);
/*
اگر به هر دلیلی میخواهید کاربر را از حساب کاربری خود
خارج کنید، از متود زیر استفاده کنید. همچنین پیشنهاد میشود
SecurityStamp کاربر رو هم از طریق متود زیر آپدیت کنید
که مطمئن شویم کاربر از حساب خود خارج میشود
*/
await _userImmediateActionsService.SignOutAsync(model.UserId);
await _userManager.UpdateSecurityStampAsync(await _userManager.FindByIdAsync(model.UserId));
}
return View(model);
}
نکته : پیشنهاد میشود موارد مربوط به داکیومنت حتما خوانده شود.
( پیشنهاد میشود قبل ازخواندن این متن، با مطالب ارائه شده در قسمت سرویس ها آشنا باشید )
در این سرویس دو متود وجود دارد RefreshCookie
و SignOut
. که در هر دو این متود ها یک متود Async هم دارند و همچنین هر دو یک ای دی کاربر به عنوان پارامتر دریافت میکنند. این پارامتر
ای دی ابتدا تبدیل یه یک کلید منحصر به فرد میشود و سپس به سرویس ذخیره سازی اصلی برای ذخیره کردن کلید ( ایدی کاربر ) به همراه بعضی اطلاعات مورد نیاز پاس داده میشود. در متود های
Async عملیات ذخیره سازی به صورت Async انجام خواهد شد.
اخطار :
پیشنهاد میشود در هنگام استفاده از متود SignOut
و یا SingOutAsync
، حتما SecurityStamp
کاربر رو هم با استفاده از متود UpdateSecurityStampAsync
موجود در کلاس UserManager
(
پکیج Identity) آپدیت بکنید، که مطمئن شویم کاربر در تمامی دستگاه های خودش از حساب کاربری اش خارج میشود. اگر این کار انجام نشود احتمال خارج نشدن کاربر از حساب کاربری اش در بعضی از
دستگاه ها وجود دارد.
از این سرویس به صورت توکار برای بالا بردن قابلیت تست پذیری کدهای مربوط به زمان استفاده میشود.
سرویس IImmediateActionsStore
مربوط به سیستم ذخیره سازی هستش. در این پکیج دو نوع سیستم ذخیره سازی استفاده شده است، اولین نوع سرویس IImmediateActionsStore
هستش که از این به بعد
اون رو با نام سرویس ذخیره سازی اصلی میشناسیم. مشخصه اصلی این سرویس ذخیره سازی، سرعت و پرفورمنس اون هستش، یعنی این سرویس باید سرعت بالایی در ذخیره سازی و مخصوصا خوندن اطلاعات
داشته باشه. به همین دلیل محل ذخیره سازی اطلاعات در این سرویس، یکی از انواع مختلف سیستم های Cache میباشد. به صورت پیشفرض از IMemoryCache
برای ذخیره سازی اطلاعات در این سرویس
استفاده میشود که میتوان آن را با IDistributedCache
جایگزین کرد، با استفاده از اکستنشن متود AddDefaultDistributedImmediateActionStore
.
سرویس IPermanentImmediateActionsStore
نوع دوم سیستم ذخیره سازی اطلاعات در این پکیج هستش، که از این به بعد اون رو با نام سرویس ذخیره سازی دائمی میشناسیم. مشخصه اصلی این سرویس
ذخیره سازی دائمی اطلاعات هستش. از این سرویس برای جلوگیری از حذف شدن اطلاعات در زمان ریستارت شدن اپلیکیشن استفاده میشود. به صورت توکار هنگاه صدا زده شدن متود های سرویس ذخیره ساز
اصلی، متود های سرویس ذخیره ساز دائمی هم صدا زده میشوند تا اطلاعات در این سرویس نیز ذخیره بشوند.
نکته مهم :
به صورت پیشفرض سرویس ذخیره ساز دائمی به صورت فیک پیاده سازی( Implement ) شده و به IServiceCollection
اضافه میشود. برای اضافه کردن سرویس ذخیره ساز دائمی واقعی نیاز دارید
که از اکستنشن متود AddPermanentImmediateActionsStore
استفاده کنید و سرویس اصلی خود که پیاده سازی کرده اید را بهش پاس بدهید.
سرویس IUserActionStoreKeyGenerator
مربوط به تولید کلید های منحصر به فرد برای استفاده در سرویس ذخیره سازی اصلی مورد استفاده قرار میگیره.
سرویس IUserImmediateActionsService
مربوط به متود هایی هستش که توسط شما مورد استفاده قرار میگیره. که در قسمت آموزش استفاده توضیح داده شده است
سرویس ICurrentUserWrapperService
به صورت توکار در پکیج استفاده میشود. از این سرویس در زمانی که کاربر نیاز به خارج شدن از حساب کاربری خود داره یا نیاز به refresh-signin اون هستش
استفاده میشه. به صورت پیشفرض از کلاس های UserManager
و SignInManager
( مربوط به پکیج Identity ) برای اینکار استفاده میشود. اگر نیاز دارید که سرویس شخصی خودتون رو اضافه کنید
میتونید از اکستنشن متود AddCurrentUserWrapperService
استفاده کنید و سرویس خودتون رو بهش پاس بدید.
بعد از استفاده از اکستنشن متود AddUserImmediateActions
سرویس های زیر به IServiceCollection
اضافه میشوند. اطلاعات بیشتر در مورد سرویس های اضافه شده رو میتونید در قسمت سرویس ها
بخونید.
services.AddMemoryCache();
services.AddSingleton<IDateTimeProvider, DateTimeProvider>();
services.TryAddSingleton<IPermanentImmediateActionsStore, FakePermanentImmediateActionsStore>();
services.TryAddTransient<IImmediateActionsStore, MemoryCacheImmediateActionsStore>();
services.TryAddSingleton<IUserActionStoreKeyGenerator, UserActionStoreKeyGenerator>();
services.TryAddTransient<IUserImmediateActionsService, UserImmediateActionsService>();
services.TryAddScoped(typeof(ICurrentUserWrapperService), typeof(IdentityCurrentUserWrapperService<>).MakeGenericType(builder.UserType));
اضافه کردن یک ذخیره سازدائمی. ( نیازمند ارث برای از اینترفیس IPermanentImmediateActionsStore
)
public static IdentityBuilder AddPermanentImmediateActionsStore<TPermanentStore>(this IdentityBuilder builder) where TPermanentStore : class, IPermanentImmediateActionsStor
اضافه کردن پیاده سازی (Implementation) پیشفرض برای استفاده از IDistributedCache
به عنوان سرویس ذخیره سازی اصلی.
public static IdentityBuilder AddDefaultDistributedImmediateActionStore(this IdentityBuilder builder)
اضافه کردن سرویس شخصی و کاستومایز شده برای ذخیره ساز اصلی. ( نیازمند ارث برای از اینترفیس IImmediateActionsStore
)
public static IdentityBuilder AddDistributedImmediateActionStore<TStore>(this IdentityBuilder builder) where TStore : class, IImmediateActionsStore
اضافه کردن سرویس شخصی و کاستومایز شده برای تولید کلید های مورد استفاده در سرویس ذخیره ساز اصلی. ( نیازمند ارث برای از اینترفیس IUserActionStoreKeyGenerator
)
public static IdentityBuilder AddUserActionStoreKeyGenerator<TGenerator>(this IdentityBuilder builder) where TGenerator : class, IUserActionStoreKeyGenerator
اضافه کردن سرویس شخصی و کاستومایز شده برای انجام عملیات های موردنظر برروی کاربر. ( نیازمند ارث برای از اینترفیس IUserImmediateActionsService
)
public static IdentityBuilder AddUserImmediateActionsService<TActionService>(this IdentityBuilder builder) where TActionService : class, IUserImmediateActionsService
اضافه کردن سرویس شخصی و کاستومایز شده برای گرفتن اطلاعات و انجام عملیات بر روی کاربر ( این سرویس به صورت توکار در پکیج استفاده میشود ). ( نیازمند ارث برای از
اینترفیس ICurrentUserWrapperService
)
public static IdentityBuilder AddCurrentUserWrapperService<TUserWrapperService>(this IdentityBuilder builder) where TUserWrapperService : class, ICurrentUserWrapperService
( پیشنهاد میشود قبل ازخواندن این متن، با مطالب ارائه شده در قسمت سرویس ها آشنا باشید )
بعد از صدا زدن یکی از متود های سرویس IUserImmediateActionsService
، ای دی کاربر پاس داده شده به متود موردنظر به یک کلید تبدیل میشود، با استفاده از IUserActionStoreKeyGenerator
.
بعد از آن یک مدل ImmediateActionDataModel
به سرویس ذخیره سازی اصلی ( و ذخیره سازی دائمی، اگر اضافه شده باشد ) اضافه خواهد شد که این مدل اضافه شده حاوی اطلاعات مورد نیاز
برای انجام عملیات روی کاربر مورد نظر میباشد. سپس در UserImmediateActionsMiddleware
بررسی میشود که اگر کاربری که Request فرستاده است، اگر ای دی کاربری اش در سرویس ذخیره سازی
اصلی وجود داشته باشد عملیات موردنظر (مثلا SignOut)
برای او انجام میشود.
اگر از این پروژه خوشتون اومده یا دارید ازش در اپلیکیشن خود استفاده میکنید، لطفا به این ریپو یک ستاره بدید. ممنون!