سفارشی سازی ASP.NET Core Identity - قسمت پنجم - سیاستهای دسترسی پویا
نویسنده: وحید نصیری
تاریخ: ۱۳۹۵/۱۱/۱۴ ۸:۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
[Authorize(Roles = ConstantRoles.Admin)] public class RolesManagerController : Controller
[Authorize(Policy="RequireAdministratorRole")]
public IActionResult Get()
{
/* .. */
} public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdministratorRole", policy => policy.RequireRole("Admin"));
});
} [Authorize(Roles = "Administrator, PowerUser, BackupAdministrator")]
options.AddPolicy("ElevatedRights", policy => policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator")); [Authorize(Policy = "ElevatedRights")]
public IActionResult Shutdown()
{
return View();
} services.AddAuthorization(options =>
{
options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber"));
}); [Authorize(Policy = "EmployeeOnly")]
public IActionResult VacationBalance()
{
return View();
} public class DynamicPermissionRequirement : IAuthorizationRequirement
{
} public class DynamicPermissionsAuthorizationHandler : AuthorizationHandler<DynamicPermissionRequirement>
{
private readonly ISecurityTrimmingService _securityTrimmingService;
public DynamicPermissionsAuthorizationHandler(ISecurityTrimmingService securityTrimmingService)
{
_securityTrimmingService = securityTrimmingService;
_securityTrimmingService.CheckArgumentIsNull(nameof(_securityTrimmingService));
}
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
DynamicPermissionRequirement requirement)
{
var mvcContext = context.Resource as AuthorizationFilterContext;
if (mvcContext == null)
{
return Task.CompletedTask;
}
var actionDescriptor = mvcContext.ActionDescriptor;
var area = actionDescriptor.RouteValues["area"];
var controller = actionDescriptor.RouteValues["controller"];
var action = actionDescriptor.RouteValues["action"];
if(_securityTrimmingService.CanCurrentUserAccess(area, controller, action))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return Task.CompletedTask;
}
} private static void addDynamicPermissionsPolicy(this IServiceCollection services)
{
services.AddScoped<IAuthorizationHandler, DynamicPermissionsAuthorizationHandler>();
services.AddAuthorization(opts =>
{
opts.AddPolicy(
name: ConstantPolicies.DynamicPermission,
configurePolicy: policy =>
{
policy.RequireAuthenticatedUser();
policy.Requirements.Add(new DynamicPermissionRequirement());
});
});
} [Authorize(Policy = ConstantPolicies.DynamicPermission)]
[DisplayName("کنترلر نمونه با سطح دسترسی پویا")]
public class DynamicPermissionsSampleController : Controller public interface IMvcActionsDiscoveryService
{
ICollection<MvcControllerViewModel> MvcControllers { get; }
ICollection<MvcControllerViewModel> GetAllSecuredControllerActionsWithPolicy(string policyName);
} [Authorize(Policy = ConstantPolicies.DynamicPermission)]
return user.HasClaim(claim => claim.Type == ConstantPolicies.DynamicPermissionClaimType && claim.Value == currentClaimValue);
public override void Process(TagHelperContext context, TagHelperOutput output)
{
context.CheckArgumentIsNull(nameof(context));
output.CheckArgumentIsNull(nameof(output));
// don't render the <security-trimming> tag.
output.TagName = null;
if(_securityTrimmingService.CanCurrentUserAccess(Area, Controller, Action))
{
// fine, do nothing.
return;
}
// else, suppress the output and generate nothing.
output.SuppressOutput();
} <security-trimming asp-area="" asp-controller="DynamicPermissionsTest" asp-action="Products">
<li>
<a asp-controller="DynamicPermissionsTest" asp-action="Products" asp-area="">
<span class="left5 fa fa-user" aria-hidden="true"></span>
گزارش از لیست محصولات
</a>
</li>
</security-trimming> var ticketStore = provider.GetService<ITicketStore>(); identityOptionsCookies.ApplicationCookie.SessionStore = ticketStore; // To manage large identity cookies
if (mvcContext.HttpContext.Request.Method.Equals("post", StringComparison.OrdinalIgnoreCase))
{
foreach (var item in mvcContext.HttpContext.Request.Form)
{
var formField = item.Key;
var formFieldValue = item.Value;
}
} var currentClaimValue = $"{area}:{controller}:{action}" public bool CanUserAccess(ClaimsPrincipal user, string area, string controller, string action)
{
var currentClaimValue = $"{area}:{controller}:{action}";
var securedControllerActions = _mvcActionsDiscoveryService.GetAllSecuredControllerActionsWithPolicy(ConstantPolicies.DynamicPermission);
if (!securedControllerActions.SelectMany(x => x.MvcActions).Any(x => x.ActionId == currentClaimValue))
{
throw new KeyNotFoundException($@"The `secured` area={area}/controller={controller}/action={action} with `ConstantPolicies.DynamicPermission` policy not found. Please check you have entered the area/controller/action names correctly and also it's decorated with the correct security policy.");
}
if (!user.Identity.IsAuthenticated)
{
return false;
}
if (user.IsInRole(ConstantRoles.Admin))
{
// Admin users have access to all of the pages.
return true;
}
// Check for dynamic permissions
// A user gets its permissions claims from the `ApplicationClaimsPrincipalFactory` class automatically and it includes the role claims too.
return user.HasClaim(claim => claim.Type == ConstantPolicies.DynamicPermissionClaimType &&
claim.Value == currentClaimValue);
} public bool CanUserAccess(ClaimsPrincipal user, string area, string controller, string action)
{
if (!user.Identity.IsAuthenticated)
{
return false;
}
if (user.IsInRole(ConstantRoles.Admin))
{
// Admin users have access to all of the pages.
return true;
}
var currentClaimValue = $"{area}:{controller}:{action}";
var securedControllerActions = _mvcActionsDiscoveryService.GetAllSecuredControllerActionsWithPolicy(ConstantPolicies.DynamicPermission);
if (!securedControllerActions.SelectMany(x => x.MvcActions).Any(x => x.ActionId == currentClaimValue))
{
throw new KeyNotFoundException($@"The `secured` area={area}/controller={controller}/action={action} with `ConstantPolicies.DynamicPermission` policy not found. Please check you have entered the area/controller/action names correctly and also it's decorated with the correct security policy.");
}
// Check for dynamic permissions
// A user gets its permissions claims from the `ApplicationClaimsPrincipalFactory` class automatically and it includes the role claims too.
return user.HasClaim(claim => claim.Type == ConstantPolicies.DynamicPermissionClaimType &&
claim.Value == currentClaimValue);
} | مشاهده فرم ویرایش | SampleController:Edit | ✓ |
| مشاهده محتویات دراپ دان | SampleController:GetData | ✓ |
public IActionResult Users_Read([DataSourceRequest] DataSourceRequest request)
{
return Json(_userManager.Users.ToDataSourceResult(request));
} @(Html.Kendo().Grid<User>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.FirstName).Width(140);
columns.Bound(c => c.LastName).Width(140);
columns.Bound(c => c.UserName).Width(140);
})
.HtmlAttributes(new { style = "height: 380px;" })
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.ButtonCount(5))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("Users_Read", "UserManager"))
)
)
اگر ممکنه باشه میخوام شبیه مثال خودتون، برای این متد دستری اعمال نکنم. آیا این امکان دارد؟ یا حتما باید شبیه Actionهای دیگر دسترسی پویا براش در نظر بگیرم؟
.Read(read => read.Action("Users_Read", "UsersManager", new { area = AreaConstants.IdentityArea }))
public class ApplicationClaimsTransformation : IClaimsTransformation
{
} services.AddScoped<IClaimsTransformation, ApplicationClaimsTransformation>();
$("#dialog").dialog({ autoOpen: false, open: function (event, ui) { $(this).load(url); }) });
<div id="dialog" title="Basic dialog">
<p>Dialog box</p>
</div> complete: function (xhr, status) {
if (xhr.status === 403 || xhr.status === 401) { $("#success").load(url, function( response, status, xhr ) {
if (xhr.status === 403 || xhr.status === 401) {
window.location = xhr.getResponseHeader('Location');
}
});
InvalidOperationException: Unable to resolve service for type 'DNTCommon.Web.Core.IMvcActionsDiscoveryService' while attempting to activate '[ProjectName].Services.SecurityTrimmingService'.
var request = mvcContext.HttpContext.Request;
if (request.Method.Equals("post", StringComparison.OrdinalIgnoreCase))
{
if (request.IsAjaxRequest() && request.ContentType.Contains("application/json"))
{
var httpRequestInfoService = mvcContext.HttpContext.RequestServices.GetService<IHttpRequestInfoService>();
var model = await httpRequestInfoService.DeserializeRequestJsonBodyAsAsync<RoleViewModel>();
if (model != null)
{
}
}
else
{
foreach (var item in request.Form)
{
var formField = item.Key;
var formFieldValue = item.Value;
}
}
} var roles = ((ClaimsIdentity)User.Identity).Claims
.Where(c => c.Type == ClaimTypes.Role)
.Select(c => c.Value);
سلام
آیا باید جاییکه کلاینت تعریف میشود 2 نمونه از کلاینت ساخته شود؟
و اینکه در هر پروژه چگونه باید از این کلاینتها استفاده کرد؟
context.Resource is AuthorizationFilterContext mvcContext
InvalidOperationException: Unable to resolve service for type 'ServiceLayer.ISecurityTrimmingService' while attempting to activate 'ServiceLayer.DynamicPermissionsAuthorizationHandler'.
public class DynamicPermissionsAuthorizationHandler : AuthorizationHandler<DynamicPermissionRequirement>
{
private readonly ISecurityTrimmingService _securityTrimmingService;
public DynamicPermissionsAuthorizationHandler(ISecurityTrimmingService securityTrimmingService)
{
_securityTrimmingService = securityTrimmingService;
_securityTrimmingService.CheckArgumentIsNull(nameof(_securityTrimmingService));
}
اینم کد تولید توکنه
public async Task<string> GenerateTokenAsync(ApplicationUser User)
{
var secretKey = Encoding.UTF8.GetBytes(_siteSettings.JwtSettings.SecretKey);
var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(secretKey), SecurityAlgorithms.HmacSha256Signature);
var encrytionKey = Encoding.UTF8.GetBytes(_siteSettings.JwtSettings.EncrypKey);
var encryptingCredentials = new EncryptingCredentials(new SymmetricSecurityKey(encrytionKey), SecurityAlgorithms.Aes128KW, SecurityAlgorithms.Aes128CbcHmacSha256);
var tokenDescriptor = new SecurityTokenDescriptor()
{
Issuer = _siteSettings.JwtSettings.Issuer,
Audience = _siteSettings.JwtSettings.Audience,
IssuedAt = DateTime.Now,
NotBefore = DateTime.Now.AddMinutes(_siteSettings.JwtSettings.NotBeforeMinutes),
Expires = DateTime.Now.AddMinutes(_siteSettings.JwtSettings.ExpirationMinutes),
SigningCredentials = signingCredentials,
Subject = new ClaimsIdentity(await GetClaimsAsync(User)),
EncryptingCredentials = encryptingCredentials,
};
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(securityToken);
}
public async Task<IEnumerable<Claim>> GetClaimsAsync(ApplicationUser User)
{
var Claims = new List<Claim>()
{
new Claim(ClaimTypes.Name,User.UserName),
new Claim(ClaimTypes.NameIdentifier,User.Id),
new Claim(ClaimTypes.MobilePhone,User.PhoneNumber),
new Claim(new ClaimsIdentityOptions().SecurityStampClaimType,User.SecurityStamp),
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())
};
var Roles = _roleManager.Roles.ToList();
foreach (var item in Roles)
{
var RoleClaims = await _roleManager.FindClaimsInRole(item.Id);
foreach (var claim in RoleClaims.Claims)
{
Claims.Add(new Claim(ConstantPolicies.DynamicPermissionClaimType, claim.ClaimValue));
}
}
foreach (var item in Roles)
Claims.Add(new Claim(ClaimTypes.Role, item.Name));
return Claims;
} توی پروژه ما backendبا .netoreو frontهم با react هست
{
"DataTokens":{},
"Routers":[],
"Values":{"page":"/Index","id":"101273123"}
} exec sp_executesql
N'UPDATE [dbo].[AppSqlCache] SET ExpiresAtTime = (CASE WHEN DATEDIFF(SECOND, @UtcNow, AbsoluteExpiration) <= SlidingExpirationInSeconds THEN AbsoluteExpiration ELSE DATEADD(SECOND, SlidingExpirationInSeconds, @UtcNow) END) WHERE Id = @Id AND @UtcNow <= ExpiresAtTime AND SlidingExpirationInSeconds IS NOT NULL AND (AbsoluteExpiration IS NULL OR AbsoluteExpiration <> ExpiresAtTime) ;SELECT Id, ExpiresAtTime, SlidingExpirationInSeconds, AbsoluteExpiration, Value FROM [app].[SqlCache] WHERE Id = @Id AND @UtcNow <= ExpiresAtTime;',
N'@Id nvarchar(449),@UtcNow datetimeoffset(7)',
@Id = N'AuthSessionStore-380ca866e7744f569659a3c160eca7ef',
@UtcNow = '2020-05-24 21:30:11.0837838 +00:00'; <div condition="Model.Approved">
<p>
This website has <strong surround="em">@Model.Approved</strong> been approved yet.
Visit www.contoso.com for more information.
</p>
</div>
<div condition="!User.Identity.IsAuthenticated">I'm not a valid user</div>
<div condition="User.Identity.IsAuthenticated">I can use the system</div> namespace ASPNETCoreIdentitySample.Areas.Identity.Controllers
{
[Authorize(Policy = ConstantPolicies.DynamicPermission)]
[Area(AreaConstants.IdentityArea)]
[BreadCrumb(UseDefaultRouteUrl = true, Order = 0)]
[DisplayName("کنترلر نمونه با سطح دسترسی پویا در یک ناحیه خاص")]
public class DynamicPermissionsAreaSampleController : Controller
{
[DisplayName("ایندکس")]
[BreadCrumb(Order = 1)]
public IActionResult Index()
{
return View();
}
}
}
[Authorize(Policy = ConstantPolicies.DynamicPermission)]
[Area("One")]
[DisplayName("home")]
public class HomeController : Controller
{
[DisplayName("ایندکس")]
public IActionResult Index()
{
return View();
}
} [Authorize(Policy = ConstantPolicies.DynamicPermission)]
[Area("Two")]
[DisplayName("home2")]
public class HomeController : Controller
{
[DisplayName("ایندکس")]
public IActionResult Index()
{
return View();
}
}
if (!lastControllerName.Equals(descriptor.ControllerName, StringComparison.Ordinal))
{
} lastControllerName = $"{descriptor.ControllerTypeInfo.Namespace}{descriptor.ControllerName}"; var controllerName = $"{descriptor.ControllerTypeInfo.Namespace}{descriptor.ControllerName}";
if (!lastControllerName.Equals(controllerName, StringComparison.Ordinal)) actionDescriptorCollectionProvider.ActionDescriptors.Items
اگر مقدار actionDescriptorCollectionProvider.ActionDescriptors.Items قبل از ورود به حلقه foreach بر اساس نام کنترلر مرتب شود( که کنترلرهای هم نام پشت سرهم قرار گیرند) خروجی فوق را مشاهده نخواهید کرد.
if (securedControllerActions.SelectMany(x => x.MvcActions)
.All(x => !string.Equals(x.ActionId, currentClaimValue, StringComparison.Ordinal)))
{
throw new KeyNotFoundException(
$"The `secured` area={area}/controller={controller}/action={action} with `ConstantPolicies.DynamicPermission` policy not found. Please check you have entered the area/controller/action names correctly and also it's decorated with the correct security policy.");
}