第46章 自定义静态与数据库动态授权依赖注入的定义实现

news2024/11/15 21:39:59

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(自定义静态与数据库动态授权依赖注入的定义实现)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/355205.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

作为初学者必须要了解的几种常用数据库!

现在已经存在了很多优秀的商业数据库&#xff0c;如甲骨文&#xff08;Oracle&#xff09;公司的 Oracle 数据库、IBM 公司的 DB2 数据库、微软公司的 SQL Server 数据库和 Access 数据库。同时&#xff0c;还有很多优秀的开源数据库&#xff0c;如 MySQL 数据库&#xff0c;Po…

Django框架之模型视图-使用 PostMan 对请求进行测试

使用 PostMan 对请求进行测试 PostMan 是一款功能强大的网页调试与发送网页 HTTP 请求的 Chrome 插件&#xff0c;可以直接去对我们写出来的路由和视图函数进行调试&#xff0c;作为后端程序员是必须要知道的一个工具。 安装方式1&#xff1a;去 Chrome 商店直接搜索 PostMan…

链表OJ(四)链表排序合集

目录 合并两个排序的链表 合并k个已排序的链表 单链表的排序 链表的奇偶重排 链表的奇偶重排扩展 合并两个排序的链表 描述 输入两个递增的链表&#xff0c;单个链表的长度为n&#xff0c;合并这两个链表并使新链表中的节点仍然是递增排序的。 数据范围&#xff1a; 0≤n≤…

Spark12: SparkSQL入门

一、SparkSQL Spark SQL和我们之前讲Hive的时候说的hive on spark是不一样的。hive on spark是表示把底层的mapreduce引擎替换为spark引擎。而Spark SQL是Spark自己实现的一套SQL处理引擎。Spark SQL是Spark中的一个模块&#xff0c;主要用于进行结构化数据的处理。它提供的最核…

Kubernetes入门级教程

Kubernetes入门级教程1. Introduction1.1 概述1.2 关键字介绍2. Cluster Install2.1 Big Data -- Postgres3. 基础知识3.1 Pod3.2 控制器3.3 通讯模式3.4 服务发现4. Command4.0 编辑文件4.1 在宿主机执行命令4.2 创建资源对象4.3 查询资源对象4.4 查询资源描述4.5 修改资源4.6…

Linux 交换分区与链接文件

目录 SWAP交换分区扩展 fdisk 创建分区 mkswap 将逻辑分区/主分区格式化为交换分区&#xff08;make swap&#xff09; swapon 交换分区挂载 swapoff 卸载交换分区 vim /etc/fstab 永久挂载 将文件设置为交换分区 链接文件 软链接 硬链接 SWAP交换分区扩展 交换分区…

量子力学奇妙之旅-双态系统(后)

专栏: 高质量文章导航-持续更新中 引子: 感慨:对于还原论,物质深层结构的物理定律如此的复杂,求解一个简单的双态系统已经如此困难,运用了大量的近视方法,在宇宙真理面前,我们只是虫子啊,我们固有的概念里面对逻辑自洽性,对事物发展的可预测性必然性,真实世界的有…

2023美赛F题讲解+数据领取

我们给大家准备了F题的数据&#xff0c;免费领取&#xff01;在文末 国内生产总值(GDP)可以说是一个国家经济健康状况最著名和最常用的指标之--。它通常用于确定一个国家的购买力和获得贷款的机会,为各国提出提高GDP的政策和项目提供动力。GDP“衡量一个国家在给定时间段内生产…

docker中 gitlab 安装、配置和初始化

小笔记&#xff1a;gitlab配置文件 /etc/gitlab/gitlab.rb 配置项jcLee95 的CSDN博客&#xff1a;https://blog.csdn.net/qq_28550263?spm1001.2101.3001.5343 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/1…

运动款蓝牙耳机哪个品牌好、市面最火爆的运动耳机推荐

我们都知道运动最不可或缺的就是音乐了&#xff0c;它俩是天生的好搭档&#xff0c;所以凡是很经常运动的小伙伴一定会去单独选择一款超好用的运动耳机&#xff0c;来增强运动体验效果&#xff0c;那么市面上的运动耳机那么多&#xff0c;怎么选择一款好用的运动耳机呢&#xf…

MySql 函数

1、简述 函数 是指一段可以直接被另一段程序调用的程序或代码。 也就意味着&#xff0c;这一段程序或代码在MySQL中已经给我们提供了&#xff0c;我们要做的就是在合适的业务场景调用对应的函数完成对应的业务需求即可。 MySQL中的函数主要分为以下四类&#xff1a; 字符串函数…

【TypeScrip】TypeScrip的任意类型(Any 类型 和 unknown 顶级类型):

文章目录一、安转依赖&#xff1a;【1】nodejs 环境执行ts【2】使用ts-node二、Any 类型 和 unknown 顶级类型【1】没有强制限定哪种类型&#xff0c;随时切换类型都可以 我们可以对 any 进行任何操作&#xff0c;不需要检查类型【2】声明变量的时候没有指定任意类型默认为any【…

基于SSM框架的生活论坛系统的设计与实现

基于SSM框架的生活论坛系统的设计与实现 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景…

已解决ImportError: cannot import name ‘featureextractor‘ from ‘radiomics‘

已解决from radiomics import featureextractor导包&#xff0c;抛出ImportError: cannot import name ‘featureextractor‘ from ‘radiomics‘异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 文章目录报错问题报错翻译报错原因解决方法联系博…

centos7给已有分区进行扩容

1、背景 最近我在虚拟机上安装软件&#xff0c;发现磁盘空间不足&#xff0c;通过上网查找资料&#xff0c;发现可以通过如下方法进行磁盘扩容&#xff0c;此处进行记录一下。 2、实现扩容 1、虚拟机上添加一个新的硬盘 2、查看我们刚刚加入的硬盘 此处我们可以看到/dev/nvm…

Seata架构篇 - TCC模式

TCC 模式 概述 TCC 是分布式事务中的两阶段提交协议&#xff0c;它的全称为 Try-Confirm-Cancel&#xff0c;即资源预留&#xff08;Try&#xff09;、确认操作&#xff08;Confirm&#xff09;、取消操作&#xff08;Cancel&#xff09;。Try&#xff1a;对业务资源的检查并…

【MySQL进阶】视图 存储过程 触发器

&#x1f60a;&#x1f60a;作者简介&#x1f60a;&#x1f60a; &#xff1a; 大家好&#xff0c;我是南瓜籽&#xff0c;一个在校大二学生&#xff0c;我将会持续分享Java相关知识。 &#x1f389;&#x1f389;个人主页&#x1f389;&#x1f389; &#xff1a; 南瓜籽的主页…

Unity3D -知识点(1)

1.场景视图鼠标滚轮&#xff1a;场景放大缩小鼠标右键&#xff1a;场景左右平移场景编辑器中&#xff0c;能看到什么&#xff1f;网格&#xff0c;每一格大小为1unit&#xff0c;建模不同&#xff0c;规定不同&#xff0c;(对应屏幕上100个像素)世界坐标系y轴向上为正x轴向右为…

每天10个前端小知识 【Day 18】

前端面试基础知识题 1.如何实现单行&#xff0f;多行文本溢出的省略样式&#xff1f; 在日常开发展示页面&#xff0c;如果一段文本的数量过长&#xff0c;受制于元素宽度的因素&#xff0c;有可能不能完全显示&#xff0c;为了提高用户的使用体验&#xff0c;这个时候就需要…

2023金三银四跳槽必会Java核心知识点笔记整理

现在互联网大环境不好&#xff0c;互联网公司纷纷裁员并缩减 HC&#xff0c;更多程序员去竞争更少的就业岗位&#xff0c;整的 IT 行业越来越卷。身为 Java 程序员的我们就更不用说了&#xff0c;上班 8 小时需要做好本职工作&#xff0c;下班后还要不断提升技能、技术栈&#…