1 数据库动态授权表授权原理
2 准备工作
2.1 重构Program.cs
using Framework.Infrastructure.Extensions;
var builder = WebApplication.CreateBuilder(args);
//如果启动项中不存在“appsettings.json”文件,则通过.Net(Core)的内置方法自动新建“appsettings.json”文件。
builder.Configuration.AddJsonFile("appsettings.json", true, true);
//把当前程序中所有继承了“IConfig”接口的具体实现类的实例,依赖注入到.Net(Core)内置依赖注入容器实例中,如果需要并把这些数据持久化存储到"appsettings.json"文件。
builder.Services.ConfigureApplicationSettings(builder);
//在调用以“AddScoped”注入的实例时必须的预先定义以下的定义注入到内置容器中,否则会出现逻辑异常:“Cannot consume scoped service...”
builder.Host.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = false;
options.ValidateOnBuild = true;
});
//把具体现类和中间件注入到内置依赖注入容器后,并把.NetCore框架内置依赖注入容器接口实例所存储的当前程序中的具体现类和中间件的实例通过“Engine”(引擎)单例实例存储到单例类的字典属性成员实例中。
//注意:从依赖注入到.Net(Core)框架内置容器中,获取“IServiceProvider”接口实例,必须定义在最后,
//否则“GetServices”/“GetRequiredService”方法将有可能不能获取取1个指定类的实例,因为该类的实例还没有依赖注入到.Net(Core)框架内置容器中。
builder.Services.ConfigureApplicationServices(builder);
var app = builder.Build();
app.MapControllers();
// 通过.NetCore框架的内置管道接口实例,实例化“IServiceProvider”接口实例,同时把继承于“IStartup”所有具体现类中的中间件实例集成到.NetCore框架内置管道中。
app.ConfigureRequestPipeline();
app.Run();
2.2 Services.Security.PermissionService.GetPermissionRoleByNewAsync
/// <summary>
/// 【异步获取新建权限角色映射】
/// <remarks>
/// 摘要:
/// 通过新建操作构建所有的限角色映射实例,这些构建后的实例存储到列表实例中,从而为授权操作提供数据支撑。
/// </remarks>
/// <returns>
/// 列表实例,该实例存储着新构建的所有的限角色映射实例。
/// </returns>
/// </summary>
public async Task<IList<PermissionRole>> GetPermissionRoleByNewAsync()
{
return await _permissionRoleRepository.GetEntitiesAsync(async () =>
{
var query = from permissionRole in _permissionRoleRepository.Table
join permission in _permissionRepository.Table on permissionRole.PermissionId equals permission.Id
join role in _roleRepository.Table on permissionRole.RoleId equals role.Id
select new PermissionRole { PermissionId = permission.Id, RoleId = role.Id, PermissionSingle = permission, RoleSingle = role };
return await query.ToListAsync();
}, cache => _staticCacheManager.PrepareKeyForDefaultCache(new("permission.all.permissionRoleByNew")));
}
3 自定义静态与数据库动态授权依赖注入的定义实现
3.1 Framework.Filters.PermissionsPolicy
namespace Framework.Filters
{
/// <summary>
/// 【授权策略--类】
/// <remarks>
/// 摘要:
/// 通过该实体类中的属性成员, 为数据库动态授权设定1个指定常量。
/// </remarks>
/// </summary>
public class PermissionsPolicy
{
/// <summary>
/// 【数据库动态授权策略】
/// <remarks>
/// 摘要:
/// 为数据库动态授权设定1个指定常量。
/// 注意:
/// 授权必须被限定为常量(const),否则在标记时会出现语法异常。
/// </remarks>
/// </summary>
public const string Name = "PermissionByDatabase";
}
}
3.2 Framework.Filters.PermissionPolicyItem
namespace Framework.Filters
{
/// <summary>
/// 【授权策略项--类】
/// <remarks>
/// 摘要:
/// 通过该实体类中的属性成员, 为数据库动态授权提供数据支撑,或对已经被授权的权限、角色、菜单进行存储。
/// </remarks>
/// </summary>
public class PermissionPolicyItem
{
/// <summary>
/// 【菜单编号】
/// <remarks>
/// 摘要:
/// 获取/设置菜单实体1个指定实例的长整型编号值,该编号值为指定菜单的数据库动态授权的验证提供数据支撑。
/// </remarks>
/// </summary>
public long? MenuId { get; set; }
/// <summary>
/// 【角色名】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定的角色名,该角色名用于对数据库动态授权的验证提供数据支撑。
/// </remarks>
/// </summary>
public virtual string RoleName { get; set; }
/// <summary>
/// 【URL】
/// <remarks>
/// 摘要:
/// 获取/设置1个相对路由字符串(由1个指定控制器中1个指行为方法拼接而且成),该路由字符串用于对数据库动态授权的验证提供数据支撑。
/// </remarks>
/// </summary>
public string Url { get; set; }
}
}
3.3 Framework.Filters.PermissionPolicyRequirement
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
namespace Framework.Filters
{
/// <summary>
/// 【授权策略必要数据--类】
/// <remarks>
/// 摘要:
/// 通过该实体类中的属性成员,为自定义依赖注入数据库动态授权中间件的实现提供数据支撑,或对已经被授权的权限、角色、菜单进行存储。
/// </remarks>
/// </summary>
public class PermissionPolicyRequirement : IAuthorizationRequirement
{
#region 拷贝构造方法
/// <param name="deniedAction">当拒绝1个指定用户的授权操作后,1个即将要跳转的控制器行为方法,该行为方法为拒绝授权操作提供解释性信息。</param>
/// <param name="permissionPolicyItemList">列表实例,该实例存储着授权策略项类的1/n实例。</param>
/// <param name="claimType">授权单元类型的1指定实例(这里特指:角色授权单元类型,即通过验证1个指定用户所属的所有角色实例,来验证是否具有权限)。</param>
/// <param name="issuer">用于生成所有令牌(Token)字符串实例,提供数据支撑的“签发机关”。</param>
/// <param name="audience">用于生成所有令牌(Token)字符串实例,提供数据支撑的“订阅者”。</param>
/// <param name="signingCredentials">1个指定令牌(Token)字符串的凭据/证书实例(令牌(Token)字符串的凭据/证书实例与HTTPS协议运行所需要的CA证书基本原理一样,都是通过哈希(Hash)算法生成的)。</param>
/// <param name="expiration">1个指定用户的令牌(Token)字符串的过期时间(数据库动态授权的过期时间)。</param>
/// <summary>
/// 【拷贝构造方法】
/// <remarks>
/// 摘要:
/// 通过拷贝构造方法实例化该类中的同1类型的属性成员。
/// </remarks>
/// </summary>
public PermissionPolicyRequirement(string deniedAction,
List<PermissionPolicyItem> permissionPolicyItemList,
string claimType,
string issuer,
string audience,
SigningCredentials signingCredentials,
TimeSpan expiration)
{
ClaimType = claimType;
DeniedAction = deniedAction;
PermissionPolicyItemList = permissionPolicyItemList;
Issuer = issuer;
Audience = audience;
Expiration = expiration;
SigningCredentials = signingCredentials;
}
#endregion
#region 属性
/// <summary>
/// 【授权策略项列表】
/// <remarks>
/// 摘要:
/// 获取/设置列表实例,该实例存储着授权策略项类的1/n实例。
/// </remarks>
/// </summary>
public List<PermissionPolicyItem> PermissionPolicyItemList { get; set; }
/// <summary>
/// 【拒绝行为方法】
/// <remarks>
/// 摘要:
/// 当拒绝1个指定用户的授权操作后,获取/设置1个即将要跳转的控制器行为方法,该行为方法为拒绝授权操作提供解释性信息。
/// </remarks>
/// </summary>
public string DeniedAction { get; set; }
/// <summary>
/// 【授权单元类型】
/// <remarks>
/// 摘要:
/// 获取/设置授权单元类型的1指定实例(这里特指:角色授权单元类型,即通过验证1个指定用户所属的所有角色实例,来验证是否具有权限)。
/// </remarks>
/// </summary>
public string ClaimType { internal get; set; }
/// <summary>
/// 【登录路径】
/// <remarks>
/// 摘要:
/// 获取/设置登录控制器行为方法的路由字符串,当访问1个需要授权才能访问的控制器行为方法时,如果用户没有执行登录操作,或该用户不具有访问权限,为跳转到登录页面提供数据支撑。
/// </remarks>
/// </summary>
public string LoginPath { get; set; } = "/Customer/Login";
/// <summary>
/// 【签发机关】
/// <remarks>
/// 摘要:
/// 获取/设置用于生成所有令牌(Token)字符串实例,提供数据支撑的“签发机关”。
/// </remarks>
/// </summary>
public string Issuer { get; set; }
/// <summary>
/// 【订阅者】
/// <remarks>
/// 摘要:
/// 获取/设置用于生成所有令牌(Token)字符串实例,提供数据支撑的“订阅者”。
/// </remarks>
/// </summary>
public string Audience { get; set; }
/// <summary>
/// 【过期时间】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定用户的令牌(Token)字符串的过期时间(数据库动态授权的过期时间)。
/// </remarks>
/// </summary>
public TimeSpan Expiration { get; set; }
/// <summary>
/// 【凭据/证书】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定令牌(Token)字符串的凭据/证书实例(令牌(Token)字符串的凭据/证书实例与HTTPS协议运行所需要的CA证书基本原理一样,都是通过哈希(Hash)算法生成的)。
/// </remarks>
/// </summary>
public SigningCredentials SigningCredentials { get; set; }
#endregion
}
}
3.4 Framework.Filters.PermissionPolicyHandler
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Services.Security;
using System.Security.Claims;
using System.Text.RegularExpressions;
namespace Framework.Filters
{
/// <summary>
/// 【授权策略处理器--类】
/// <remarks>
/// 摘要:
/// 通过该实体类中的方法成员来验证1个指定用户所属的所有角色实例都不拥有访问指定控制器行为方法的权限,如果没有则跳转到登录页面或授权拒绝页面;如有则执行指定控制器行为方法。
/// </remarks>
/// </summary>
public class PermissionPolicyHandler : AuthorizationHandler<PermissionPolicyRequirement>
{
#region 拷贝构造方法与变量
/// <summary>
/// 【授权方案】
/// <remarks>
/// 摘要:
/// 获取/设置身份认证方案提供程序接口的1个指定实例(这里特指:JwtBearer身份认证)。
/// </remarks>
/// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; }
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IPermissionService _permissionService;
/// <summary>
/// 【拷贝构建方法】
/// <remarks>
/// 摘要:
/// 依赖注入容器通过拷贝构造方法,实例化该类中的变量成员。
/// </remarks>
/// </summary>
public PermissionPolicyHandler(IAuthenticationSchemeProvider schemes,
IHttpContextAccessor httpContextAccessor,
IPermissionService permissionService)
{
Schemes = schemes;
_httpContextAccessor = httpContextAccessor;
_permissionService = permissionService;
}
#endregion
#region 方法--接口实现--覆写
/// <param name="context">.Net(Core)框架内置依赖注入容器实例。</param>
/// <param name="requirement">.Net(Core)框架内置依赖注入容器实例。</param>
/// <summary>
/// 【异步必要处理】
/// <remarks>
/// 摘要:
/// 通过该方法来验证1个指定用户所属的所有角色实例都不拥有访问指定控制器行为方法的权限,如果没有则跳转到登录页面或授权拒绝页面;如有则执行指定控制器行为方法。
/// </remarks>
/// </summary>
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionPolicyRequirement requirement)
{
var httpContext = _httpContextAccessor.HttpContext;
if (!requirement.PermissionPolicyItemList.Any())
{
List<PermissionPolicyItem> _permissionItemList = new List<PermissionPolicyItem>();
var data = await _permissionService.GetPermissionRoleByNewAsync();
_permissionItemList = data.Select(d => new PermissionPolicyItem
{
RoleName = d.RoleSingle.Name,
Url = d.PermissionSingle.Url,
MenuId = d.PermissionSingle.MenuId,
}).ToList();
if (httpContext != null)
{
var questUrl = httpContext.Request.Path.Value!.ToLower();
// 整体结构类似认证中间件UseAuthentication的逻辑,具体查看开源地址
// https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/Core/src/AuthenticationMiddleware.cs
httpContext.Features.Set<IAuthenticationFeature>(
new AuthenticationFeature
{
OriginalPath = httpContext.Request.Path,
OriginalPathBase = httpContext.Request.PathBase
});
// Give any IAuthenticationRequestHandler schemes a chance to handle the request
// 主要作用是: 判断当前是否需要进行远程验证,如果是就进行远程验证
var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
{
if (await handlers.GetHandlerAsync(httpContext, scheme.Name) is IAuthenticationRequestHandler handler && await handler.HandleRequestAsync())
{
context.Fail();
return;
}
}
//判断请求是否拥有凭据,即有没有登录。
var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
if (defaultAuthenticate != null)
{
var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
//result?.Principal不为空即登录成功。
if (result?.Principal != null)
{
httpContext.User = result.Principal;
// 获取1个指定用户所属的所有角色实例。
var currentUserRoles = new List<string>();
currentUserRoles = (from item in httpContext.User.Claims
where item.Type == requirement.ClaimType
select item.Value).ToList();
//验证1个指定用户所属的所有角色实例都不拥有访问指定控制器行为方法的权限。
bool _isMatchRole = false;
var permisssionRoles = _permissionItemList.Where(w => currentUserRoles.Contains(w.RoleName));
foreach (var item in permisssionRoles)
{
try
{
//验证1个指定用户所属的所有角色实例是否有访问当前控制器行为方法的权限。
if (Regex.Match(questUrl, item.Url.ToLower().Trim()).Value == questUrl)
{
_isMatchRole = true;
break;
}
}
catch (Exception)
{
}
}
//如果1个指定用户没有相应的角色实例,或该指定用户所属的所有角色实例都不拥有访问指定控制器行为方法的权限。
if (currentUserRoles.Count <= 0 || !_isMatchRole)
{
context.Fail();
return;
}
//验证1个指定用户当前Token(令牌)是否已经过期。
bool _isExpiration = false;
_isExpiration = (httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) != null
&& DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) >= DateTime.Now;
//如果过期则该指定用户不拥有访问指定控制器行为方法的权限。
if (!_isExpiration)
{
context.Fail(new AuthorizationFailureReason(this, "授权已过期,请重新授权"));
return;
}
context.Succeed(requirement);
return;
}
}
//判断没有登录时,是否访问登录的url,并且是Post请求,并且是form表单提交类型,否则为失败。
if (!questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST")
|| !httpContext.Request.HasFormContentType))
{
context.Fail();
return;
}
}
context.Succeed(requirement);
}
}
#endregion
}
}
4 抽离自定义静态与数据库动态授权依赖注入
4.1 Framework.Infrastructure.Extensions.ServiceCollectionExtensions. AddAuthorizationByDatabase
/// <param name="services">.Net(Core)框架内置依赖注入容器实例。</param>
/// <summary>
/// 【添加自定义数据库动态授权中间件】
/// <remarks>
/// 摘要:
/// 抽离自定义数据库动态授权中间件实例的依赖注入操作,为当前程序支持数据库动态授权提供方法支撑。
/// </remarks>
/// </summary>
public static void AddAuthorizationByDatabase(this IServiceCollection services)
{
//写死的授权策略(静态授权策略),使用方式例如:[Authorize(Policy = "OnlyInAdministrator")]
//说明:静态授权策略由于定义实现相对简单,一般于测试,在工程性程序中基本不会被使用。
services.AddAuthorization(options =>
{
// "包含所有权限,即用户不受权限限制(映射角色:Administrator,Register,Guest= [AllowAnonymous])"
options.AddPolicy("PermissionAll", policy => policy.RequireRole("Administrator", "Register", "Guest").Build());
options.AddPolicy("AdministratorAndRegister", policy => policy.RequireRole("Administrator", "Register"));
options.AddPolicy("OnlyInAdministrator", policy => policy.RequireRole("Administrator"));
options.AddPolicy("OnlyInRegister", policy => policy.RequireRole("Register"));
});
//从单例实例的字典成员实例中获取当前程序所有配置相关数据。
AppSettings _appSettings = Singleton<AppSettings>.Instance;
//从应用配置类实例中获取JwtBearer身份认证相关数据。
JwtBearerConfig _jwtBearerConfig = _appSettings.Get<JwtBearerConfig>();
//获取秘钥。
SymmetricSecurityKey _symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtBearerConfig.SecretKey));
//获取1个指定令牌(Token)字符串的凭据/证书实例(令牌(Token)字符串的凭据/证书实例与HTTPS协议运行所需要的CA证书基本原理一样,都是通过哈希(Hash)算法生成的)。
SigningCredentials _signingCredentials = new SigningCredentials(_symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
//自定义数据库动态授权策略。
var permission = new List<PermissionPolicyItem>();
// 设定授权策略必要数据类的1个指定实例
var permissionPolicyRequirement = new PermissionPolicyRequirement(
"/api/denied",//当拒绝1个指定用户的授权操作后,1个即将要跳转的控制器行为方法,该行为方法为拒绝授权操作提供解释性信息(目前无用)
permission,
ClaimTypes.Role,//基于角色的授权
_jwtBearerConfig.Issuer,//发行人
_jwtBearerConfig.Audience,//听众
_signingCredentials,//签名凭据
expiration: TimeSpan.FromSeconds(60 * 60)//数据库动态授权的过期时间
);
//1个指定的控制器行为方法通过对授权表动态的对验证授权权策略.
services.AddAuthorization(options =>
{
//调用数据库动态授权定义实现。
options.AddPolicy(PermissionsPolicy.Name,
policy => policy.Requirements.Add(permissionPolicyRequirement));
});
services.AddSingleton<IAuthorizationHandler, PermissionPolicyHandler>();
// 将授权必要类注入生命周期内
services.AddSingleton(permissionPolicyRequirement);
}
4.2 重构Framework.Infrastructure.AuthorizationStartup.ConfigureServices
/// <param name="services">.Net(Core)框架内置依赖注入容器实例。</param>
/// <param name="configuration">.NetCore框架内置配置接口实例(存储着当前程序中所有*.json文件中的数据)。</param>
/// <summary>
/// 【配置服务】
/// <remarks>
/// 摘要:
/// 把自定义依赖注入数据库动态授权中间件注入到内置依赖注入容器中。
/// </remarks>
/// </summary>
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddAuthorizationByDatabase();
}
注意:
必须进行重构否则错误状态码为:500
4.3 重构WebApi.Controllers.CustomerController
using Core.Configuration;
using Core.Domain.Customers;
using Core.Infrastructure;
using Framework.Filters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Services.Customers;
using Services.Security;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using WebApi.Models;
namespace WebApi.Controllers
{
[Route("[controller]/[action]")]
[ApiController]
public class CustomerController : ControllerBase
{
#region 拷贝构造方法与变量
private readonly ICustomerService _customerService;
private readonly IEncryptionService _encryptionService;
private readonly IPermissionService _permissionService;
/// <summary>
/// 【拷贝构建方法】
/// <remarks>
/// 摘要:
/// 依赖注入容器通过拷贝构造方法,实例化该类中的变量成员。
/// </remarks>
/// </summary>
public CustomerController(
ICustomerService customerService,
IEncryptionService encryptionService,
IPermissionService permissionService)
{
_customerService = customerService;
_encryptionService = encryptionService;
_permissionService = permissionService;
}
#endregion
/// <param name="login">登录模型记录的1个指定实例。</param>
/// <summary>
/// 【登录--无需权限】
/// </summary>
/// <remarks>
/// 摘要:
/// 通过登录操作获取1个指定用户的1个指定令牌(Token)字符串实例,为访问指定权限的Api提供数据支撑。
/// </remarks>
/// <returns>
/// 返回:
/// 1个指定用户的1个指定令牌(Token)字符串实例。
/// </returns>
[HttpPost]
public async Task<MessageModel<TokenViewModel>> Login([FromBody] LoginModel login)
{
if (await _customerService.GetCustomerByEmailAsync(login.Email) != null)
{
if (await _customerService.ValidateCustomerAsync(login.Email, login.Password))
{
Customer _customer = await _customerService.GetCustomerByEmailAsync(login.Email);
string _roleList = await _customerService.GetRoleNameByCustomerIdAsync(_customer.Id);
var claims = new List<Claim> {
new Claim(ClaimTypes.Email, _customer.Email),
new Claim(JwtRegisteredClaimNames.Jti, _customer.Id.ToString()),
new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(TimeSpan.FromSeconds(60 * 60).TotalSeconds).ToString()) };
claims.AddRange(_roleList.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
//从单例实例的字典成员实例中获取当前程序所有配置相关数据。
AppSettings _appSettings = Singleton<AppSettings>.Instance;
//从应用配置类实例中获取JwtBearer身份认证相关数据。
JwtBearerConfig _jwtBearerConfig = _appSettings.Get<JwtBearerConfig>();
//获取秘钥。
SymmetricSecurityKey _symmetricSecurityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_jwtBearerConfig.SecretKey));
//通过1个指定的加密算法名称,实例化。
SigningCredentials _signingCredentials = new SigningCredentials(_symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
JwtSecurityToken _jwtSecurityToken = new JwtSecurityToken(
issuer: _jwtBearerConfig.Issuer,
audience: _jwtBearerConfig.Audience,
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.Add(TimeSpan.FromSeconds(60 * 60)),
signingCredentials: _signingCredentials
);
string _token = new JwtSecurityTokenHandler().WriteToken(_jwtSecurityToken);
TokenViewModel _tokenViewModel = new TokenViewModel
{
Success = true,
Token = _token,
ExpiresIn = TimeSpan.FromSeconds(60 * 60).TotalSeconds,
TokenType = "Bearer"//基于JwtBearer身份认证方式。
};
return MessageModel<TokenViewModel>.GetSuccess("成功登录!", _tokenViewModel);
}
}
return MessageModel<TokenViewModel>.Fail("登录失败!", 500);
}
//[Authorize(Policy = "OnlyInAdministrator")]
[Authorize(PermissionsPolicy.Name)]
[HttpPost]
public async Task<MessageModel<bool>> Index([FromBody] PaginationModel pagination)
{
return MessageModel<bool>.GetSuccess("成功获取所有用户!", true);
}
//[Authorize(Policy = "AdministratorAndRegister")]
[Authorize(PermissionsPolicy.Name)]
[HttpGet]
public async Task<MessageModel<bool>> Info()
{
return MessageModel<bool>.GetSuccess("成功获取单个用户!", true);
}
[HttpGet]
public async Task<MessageModel<bool>> CreateGet()
{
return MessageModel<bool>.GetSuccess("成功添加单个用户显示!", true);
}
[HttpPost]
public async Task<MessageModel<bool>> CreatePost()
{
return MessageModel<bool>.GetSuccess("成功添加单个用户提交!", true);
}
[HttpGet]
public async Task<MessageModel<bool>> EditGet()
{
return MessageModel<bool>.GetSuccess("成功修改单个用户显示!", true);
}
[HttpPut]
public async Task<MessageModel<bool>> EditPut()
{
return MessageModel<bool>.GetSuccess("成功修改单个用户提交!", true);
}
[HttpGet]
public async Task<MessageModel<bool>> ChangePasswordGet()
{
return MessageModel<bool>.GetSuccess("成功密码修改显示!", true);
}
[HttpPut]
public async Task<MessageModel<bool>> ChangePasswordPut()
{
return MessageModel<bool>.GetSuccess("成功密码修改提交!", true);
}
[HttpDelete]
public async Task<MessageModel<bool>> Delete()
{
return MessageModel<bool>.GetSuccess("成功删除单个用户!", true);
}
[HttpDelete]
public async Task<MessageModel<bool>> DeleteSelected()
{
return MessageModel<bool>.GetSuccess("成功删除所选用户!", true);
}
}
}
5 调试
6 授权的横切特性调用与方法内置调用
授权的调用方式有两种:
第一种就是上述例子中通过横切特性来实现对控制器行为方法的权限过滤。
第二种是定义一个布尔型的授权方法,而控制器行为方法通过内置调用该布尔型的授权方法实现权限过滤。
不管是第一种权限过滤方案,还第二种权限过滤方案,其实质都是对控制器行为方法进行权限限定,其区别是:
控制器行为方法可以对权限限定进行集中管理(细粒度更大),即把横切特性标记到控件器上,这种方式更加简便,以最少修改代码的方式实现权限限定;但是第二种方案就做不到。但第二种方案也有自己的优势,即控制器行为方法可以直接返回确且的权限限定操作信息,这是是第一种方案就做不到的。
对以上功能更为具体实现和注释见:230218_040shopDemo(自定义静态与数据库动态授权依赖注入的定义实现)。