简体   繁体   English

ASP.NET Core 2.1,Angular 5:Hangfire Auth仅在登录时有效

[英]ASP.NET Core 2.1, Angular 5: Hangfire Auth only works on login

I have an ASP.NET Core 2.1 Web API that uses an Angular 5 front-end. 我有一个使用Angular 5前端的ASP.NET Core 2.1 Web API。 When I call the Login() method, it saves a Cookie to the session. 当我调用Login()方法时,它将Cookie保存到会话中。

Response.Cookies.Append("UserRole", userFromRepo.UserRole.ToString());

Then when accessing the Hangfire dashboard, I check for that cookie, and authorize if the user is an Admin (See Startup.cs below). 然后在访问Hangfire仪表板时,我检查该cookie,并授权该用户是否为管理员(请参见下面的Startup.cs)。

However, since I am using JWT tokens, and the front-end token doesn't expire right away, if the user closes the browser and re-opens my site, they don't have to log in, but it is a new session, so the cookie no longer exists. 但是,由于我正在使用JWT令牌,并且前端令牌不会立即过期,因此如果用户关闭浏览器并重新打开我的网站,则不必登录,但这是一个新会话,因此Cookie不再存在。

Is there a more persistent way to store the user's role? 有没有更持久的方法来存储用户的角色? (no, I'm not using Identity) Or is there a way to re-instantiate the cookie at the startup of the new session? (不,我没有使用Identity)还是有办法在新会话启动时重新实例化cookie?


AuthController.cs AuthController.cs

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] UserForLoginDto userForLoginDto)
    {
        var userFromRepo = await _repo.Login(userForLoginDto.Username.ToLower(), userForLoginDto.Password);

        //stuff to generate tokenString

        Response.Cookies.Append("UserRole", userFromRepo.UserRole.ToString());

        return Ok(new { tokenString, user });
    }


Startup.cs Startup.cs

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

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHangfire(config =>
            config.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
        services.AddMvc()
            .AddJsonOptions(opt =>
            {
                opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        services.AddScoped<IAuthRepository, AuthRepository>();

        services.AddScoped<IBaseRepository, BaseRepository>();

        services.AddSingleton(Configuration);

        var key = Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value);

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/dist";
        });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseAuthentication();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler(builder =>
            {
                builder.Run(async context =>
                {
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

                    var error = context.Features.Get<IExceptionHandlerFeature>();
                    if (error != null)
                    {
                        context.Response.AddApplicationError(error.Error.Message);
                        await context.Response.WriteAsync(error.Error.Message);
                    }
                });
            });
        }

        app.UseCors(x => x.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials());

        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
        app.UseHangfireDashboard("/hangfire", new DashboardOptions()
        {
            Authorization = new[] {new HangfireAuthorizationFilter()}
        });

        app.UseHangfireServer();

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseSpaStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller}/{action=Index}/{id?}");
        });

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
            }
        });
    }
}

public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
    public bool Authorize([NotNull] DashboardContext context)
    {
        try
        {
            var httpContext = context.GetHttpContext();

            var userRole = httpContext.Request.Cookies["UserRole"];
            return userRole == UserRole.Admin.ToString();
        }
        catch
        {
            return false;
        }
    }
}


AuthController.cs AuthController.cs

Ok, a couple months later, I came back to this... here's how I got it to work! 好的,几个月后,我又回到了...这是我如何使其工作的方法!

  • Connect to the DB, get the current user via ID, and add an identity claim within the authentication events section that contains the user's role, and use AddCookie() to save the value within request's cookies (within ConfigureServices ) 连接到数据库,通过ID获取当前用户,并在包含用户角色的身份验证事件部分中添加身份声明,并使用AddCookie()将值保存在请求的Cookie中(在ConfigureServices

  • Create an HangfireAuthorizationFilter that searches for the UserRole cookie and compares it to my UserRoles enum. 创建一个HangfireAuthorizationFilter来搜索UserRole cookie,并将其与我的UserRoles枚举进行比较。

  • Use my custom AuthorizationFilter when starting Hangfire (within Configure ) 启动Hangfire时使用我的自定义AuthorizationFilter(在Configure
  • Startup.cs Startup.cs

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
    
        }
    
        public IConfiguration Configuration { get; }
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<DataContext>(x => x
                .UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                    b =>
                    {
                        b.MigrationsAssembly(("MyApp"));
                        b.EnableRetryOnFailure();
                    })
                .ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.IncludeIgnoredWarning)));
    
            services.AddMvc()
                .AddJsonOptions(opt =>
                {
                    opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.Events = new JwtBearerEvents
                    {
                        OnTokenValidated = async ctx =>
                        {
                            var clientId = ctx.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
                            var db = ctx.HttpContext.RequestServices.GetRequiredService<DataContext>();
                            var user = await db.Users.FirstOrDefaultAsync(u => u.Id == int.Parse(clientId));
    
                            if (user != null)
                            {
                                var userRole = user.UserRole;
                                var claims = new List<Claim>
                                {
                                    new Claim(ClaimTypes.Role, userRole.ToString())
                                };
                                var appIdentity = new ClaimsIdentity(claims);
                                ctx.Principal.AddIdentity(appIdentity);
                            }
                        }
                    };
    
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(key),
                        ValidateIssuer = false,
                        ValidateAudience = false
                    };
                }).AddCookie();
    
            //...
        }
    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            app.UseAuthentication();
    
            app.UseHangfireDashboard("/hangfire", new DashboardOptions()
            {
                Authorization = new[] { new HangfireAuthorizationFilter() }
            });
            app.UseHangfireServer();
    
            //...
        }
    }
    
    public class HangfireAuthorizationFilter : ControllerBase, IDashboardAuthorizationFilter
    {
        public bool Authorize([NotNull] DashboardContext context)
        {
            try
            {
    
                var httpContext = context.GetHttpContext();
                var userRole = httpContext.Request.Cookies["UserRole"];
                return userRole == UserRole.Admin.ToString();
            }
            catch
            {
                return false;
            }
        }
    }
    

    声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

     
    粤ICP备18138465号  © 2020-2024 STACKOOM.COM