如何从 .net core 中的 jwt 令牌中获取用户的 id 或如何从自定义授权属性返回值?

问题描述

我通过以下方式创建我的令牌

            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name,user.Id.ToString()),new Claim(ClaimTypes.Role,"tada")
                }),Expires = DateTime.UtcNow.AddDays(7),SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.Createtoken(tokenDescriptor);
            var encryptedtoken = tokenHandler.Writetoken(token);

现在我想简单地从我的授权属性获取用户 ID 并以某种方式将其放入上下文中? 我知道我可以像这样解码令牌

        [Authorize(Roles = "tada")]
        public IActionResult Get()
        {
            var token = HttpContext.Request.Headers[HeaderNames.Authorization][0];
            var tokenArray = token.Split(" ");
            var handler = new JwtSecurityTokenHandler();
            var tokenS = handler.ReadToken(tokenArray[1]) as JwtSecurityToken;
            return Ok(tokenS.Payload.SingleOrDefault(t => t.Key == "unique_name").Value);
        }

但是我如何以更聪明的方式重用这段代码,我可以创建自己的授权属性,如果没有办法将其存储在上下文中,我如何创建单例/范围/瞬态服务?

这是我如何配置 jwt

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<CatstagramDbContext>(options =>
                options.UsesqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddDatabaseDeveloperPageExceptionFilter();

            services.AddIdentity<User,IdentityRole>(options =>
            {
                options.Password.requiredigit = false;
                options.Password.RequireLowercase = false;
                options.Password.RequireUppercase = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.requiredLength = 6;
            })
                .AddEntityFrameworkStores<CatstagramDbContext>();
            var applicationSettingConfiguration = Configuration.GetSection("ApplicationSettings");
            services.Configure<AppSettings>(applicationSettingConfiguration);

            var appSettings = applicationSettingConfiguration.Get<AppSettings>();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.Savetoken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(key),ValidateIssuer = false,ValidateAudience = false
                };
            });
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseMigrationsEndPoint();
            }
            app.UseCors(options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                
            });
            app.ApplyMigrations();
        }
    }

解决方法

我正在使用此函数获取任何令牌声明值

public static string GetClaimValue(HttpContext httpContext,string valueType)
        {
            if (string.IsNullOrEmpty(valueType)) return null;
            var identity = httpContext.User.Identity as ClaimsIdentity;
            var valueObj = identity == null ? null : identity.Claims.FirstOrDefault(x => x.Type == valueType);
            return valueObj==null? null:valueObj.Value;
        }

你可以这样使用它

var name = GetClaimValue(HttpContext,"unique_name");
,

当身份验证中间件对请求进行身份验证时,它会使用保存当前用户声明的 HttpContext.User 填充 ClaimsPrincipal 属性。

ClaimsPrincipal 类在名为 System.Security.Claims 的命名空间中的 FindFirstValue 中有一个扩展方法。

User.FindFirstValue("unique_name");

为您提供第一个 unique_name 声明的值。

来源:https://github.com/dotnet/aspnetcore/blob/2be49d930a5fb53e781abd175c3b2a8f8b7827d4/src/Identity/Extensions.Core/src/PrincipalExtensions.cs