Authentication ASP.Net MVC 6 Windows身份验证自定义授权自定义角色检查来自数据库

Authentication ASP.Net MVC 6 Windows身份验证自定义授权自定义角色检查来自数据库,authentication,asp.net-core-mvc,Authentication,Asp.net Core Mvc,我想用ASP.NETMVC6创建一个内部网应用程序 我正在使用windows身份验证,我希望根据数据库表设置不同的规则 例如,如果我想限制某些用户从函数或控制器访问 // GET: TestingAuths [Authorize(Roles ="administrator")] public IActionResult Index() { return View(_context.MyTestingAuth.ToList()); } 如何

我想用ASP.NETMVC6创建一个内部网应用程序

我正在使用windows身份验证,我希望根据数据库表设置不同的规则

例如,如果我想限制某些用户从函数或控制器访问

    // GET: TestingAuths
    [Authorize(Roles ="administrator")]
    public IActionResult Index()
    {
        return View(_context.MyTestingAuth.ToList());
    }
如何检查登录的用户是否具有数据库角色表中的角色管理员。 以下是一个解决方案,但它不适用于ASP.Net MVC 6:


我想要一个ASP.Net MVC 6的解决方案理想情况下,您的身份/身份验证提供商将在声明身份中提供角色声明(如果由您控制)

但是,另一种方法是编写自己的AuthorizationHandler来拦截mvc调用

public class CustomAuthorizationRequirement : AuthorizationHandler<CustomAuthorizationRequirement>, IAuthorizationRequirement
{
    private readonly AppDBContext _context;
    public CustomAuthorizationRequirement(AppDBContext context)
    {
        _context = context;
    }

    protected override void Handle(AuthorizationContext context, CustomAuthorizationRequirement requirement)
    {
        var isValid = false;

        //perform any checks you want here i.e. check for authorization filters and validate against your database roles
        //Due to the 2 different versions of AuthorizationContext I have hard referenced this
        if(context.Resource is Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext)
        {
            //Get the MVC authorization context
            var authContext = (Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext)context.Resource;

            //Find the AuthorizeAttribute from the given function
            var authAttribute = authContext.Filters.OfType<AuthorizeAttribute>().FirstOrDefault();

            foreach(var role in authAttribute.Roles.Split(new char[] {','}))
            {
                var isInRole = _context.Set<ApplicationUser>().Count(u => u.UserName == context.User.Name && u.UserRoles.Contains(role) > 0);
                if (isInRole)
                    isValid = true;

            }
        }


        if (isValid )
            context.Succeed(requirement);
        else
            context.Fail();
    }
}

您应该查看代码中的策略,而不是进行角色检查

需求的处理程序可以在其构造函数中获取DI元素,因此您可以在DI中注册RoleRepository,然后在处理程序构造函数中获取它。然后使用参数化需求来配置策略

比如说,

public class MyRoleRequirement : IAuthorizationRequirement
{
    public MyRoleRequirement(string roles)
    {
        Roles = roles;
    }

    public string Roles { get; set; }
}
现在,让我们假设您的角色存储库是从IRolesRepository继承的,带有IsInRole(字符串角色,ClaimsPrincipal用户)函数。在你的处理程序中,你会做如下的事情

public class MyRoleAuthorizationHandler : AuthorizationHandler<MyRoleRequirement>
{
    IRolesRepository _rolesRepository;

    public MyRoleAuthorizationHandler(IRolesRepository rolesRepository)
    {
        _employeeRepository = employeeRepository;
    }

    protected override void Handle(AuthorizationContext context, 
                                   MyRoleRequirement requirement)
    {
        if (_rolesRepository.IsInRole(requirement.Roles, context.User)
        {
            context.Succeed(requirement);
        }
    }
}
公共类MyRoleAuthorizationHandler:AuthorizationHandler
{
IRolesRepository(角色存储);;
公共MyRoleAuthorizationHandler(IRolesRepository rolesRepository)
{
_employeeRepository=employeeRepository;
}
受保护的覆盖无效句柄(AuthorizationContext上下文,
MyRoleRequirement要求)
{
if(_rolesRepository.IsInRole(requirement.Roles,context.User)
{
成功(要求);
}
}
}
然后,您只需在ConfigureServices()中的startup.cs中配置策略和处理程序,并记住在DI系统中注册您的角色存储库,然后就可以了

看起来像

services.AddAuthorization(options =>
{
    options.AddPolicy("Administrators", policy =>
    { 
        policy.Requirements.Add(new MyRolesRequirement("Administrator));
    });
});

services.AddSingleton<IAuthorizationHandler, MyRolesAuthorizationHandler>();
services.AddAuthorization(选项=>
{
options.AddPolicy(“管理员”,策略=>
{ 
政策。要求。添加(新的我的角色要求(“管理员”);
});
});
services.AddSingleton();
在文档中按原样显示


请注意,此代码是在输入框中完成的,而不是在VS中完成的,因此可能无法编译:)

我想您现在可以使用此代码,但对于我在学习MVC和.Net Core时使用的Intranet,我使用了基于索赔的授权,这取决于针对此人的数据库值

我是这样做的,这无疑是可以改进的,但希望这会及时到来

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
 services.AddMvc(config =>
 {
    var policy = new AuthorizationPolicyBuilder()
                     .RequireAuthenticatedUser()
                     .Build();
    config.Filters.Add(new AuthorizeFilter(policy));
 })

 services.AddAuthorization(options =>
 {
    options.AddPolicy("Administrator", policy => policy.RequireClaim("Administrator"));
 });

 services.Configure<IISOptions>(options =>
 {
    options.ForwardWindowsAuthentication = true;
 });

 var connection = etc etc;
 services.AddDbContext<IntranetContext>(options => options.UseSqlServer(connection));

 services.AddScoped<IClaimsTransformer, ClaimsTransformer>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
        app.UseSession();
        app.UseDefaultFiles();
        app.UseStaticFiles();
        app.UseClaimsTransformation(async (context) =>
        {
            IClaimsTransformer transformer = context.Context.RequestServices.GetRequiredService<IClaimsTransformer>();
            return await transformer.TransformAsync(context);
        });

        app.UseStatusCodePages();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
public class ClaimsTransformer : IClaimsTransformer
{
    private readonly IntranetContext dbcontext;

    /// <summary>
    /// Initializes a new instance of the <see cref="ClaimsTransformer" /> class.
    /// </summary>
    /// <param name="context">Also to be written.</param>
    public ClaimsTransformer(IntranetContext context)
    {
        this.dbcontext = context;
    }

    /// <summary>
    /// Manages claims against the ClaimsPrincipal for Authenticated Users
    /// </summary>
    /// <param name="context">Also to be written.</param>
    /// <returns>Still to be written.</returns>
    public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
        System.Security.Principal.WindowsIdentity windowsIdentity = null;

        foreach (var i in context.Principal.Identities)
        {
            if (i.GetType() == typeof(System.Security.Principal.WindowsIdentity))
            {
                windowsIdentity = (System.Security.Principal.WindowsIdentity)i;
            }
        }

        if (windowsIdentity != null)
        {
            var username = windowsIdentity.Name.Remove(0, 6);
            var appUser = this.dbcontext.Person.FirstOrDefault(m => m.Username == username);

            if (appUser != null)
            {
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Id", Convert.ToString(appUser.Id), ClaimValueTypes.Integer));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Fullname", appUser.Firstname + ' ' + appUser.Surname, ClaimValueTypes.String));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Firstname", appUser.Firstname, ClaimValueTypes.String));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Surname", appUser.Surname, ClaimValueTypes.String));

                if (appUser.Administrator)
                {
                    ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Administrator", "1", ClaimValueTypes.Boolean));
                }
            }
            else
            {
                Person newPerson = new Person();
                newPerson.Username = username;
                newPerson.Firstname = username.Split('.')[0].ToString().ToTitleCase();
                newPerson.Surname = username.Split('.')[1].ToString().ToTitleCase();
                newPerson.LocationId = 1;
                newPerson.CreatedBy = 1;
                newPerson.CreatedDate = DateTime.Now;
                newPerson.Email = username + "@mycompany.com";
                this.dbcontext.Add(newPerson);
                await this.dbcontext.SaveChangesAsync();

                appUser = this.dbcontext.Person.FirstOrDefault(m => m.Username == username);
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Id", Convert.ToString(appUser.Id), ClaimValueTypes.Integer));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Fullname", appUser.Firstname + ' ' + appUser.Surname, ClaimValueTypes.String));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Firstname", appUser.Firstname, ClaimValueTypes.String));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Surname", appUser.Surname, ClaimValueTypes.String));
            }
        }

        return await System.Threading.Tasks.Task.FromResult(context.Principal);
    }
}
public void配置服务(IServiceCollection服务)
{
services.AddMvc(配置=>
{
var policy=new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()文件
.Build();
config.Filters.Add(新的授权过滤器(策略));
})
services.AddAuthorization(选项=>
{
options.AddPolicy(“管理员”,policy=>policy.requirecall(“管理员”);
});
配置(选项=>
{
options.ForwardWindowsAuthentication=true;
});
var连接=等;
services.AddDbContext(options=>options.UseSqlServer(connection));
services.addScope();
}
公共void配置(IApplicationBuilder应用程序、IHostingEnvironment环境、iLogger工厂)
{
AddConsole(this.Configuration.GetSection(“Logging”);
loggerFactory.AddDebug();
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
其他的
{
app.UseExceptionHandler(“/Home/Error”);
}
app.UseSession();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseClaimsTransformation(异步(上下文)=>
{
IClaimsTransformer transformer=context.context.RequestServices.GetRequiredService();
返回wait transformer.TransformAsync(上下文);
});
app.UseStatusCodePages();
app.UseMvc(路由=>
{
routes.MapRoute(
名称:“默认”,
模板:“{controller=Home}/{action=Index}/{id?}”);
});
}
ClaimsTransformer.cs

public void ConfigureServices(IServiceCollection services)
{
 services.AddMvc(config =>
 {
    var policy = new AuthorizationPolicyBuilder()
                     .RequireAuthenticatedUser()
                     .Build();
    config.Filters.Add(new AuthorizeFilter(policy));
 })

 services.AddAuthorization(options =>
 {
    options.AddPolicy("Administrator", policy => policy.RequireClaim("Administrator"));
 });

 services.Configure<IISOptions>(options =>
 {
    options.ForwardWindowsAuthentication = true;
 });

 var connection = etc etc;
 services.AddDbContext<IntranetContext>(options => options.UseSqlServer(connection));

 services.AddScoped<IClaimsTransformer, ClaimsTransformer>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
        app.UseSession();
        app.UseDefaultFiles();
        app.UseStaticFiles();
        app.UseClaimsTransformation(async (context) =>
        {
            IClaimsTransformer transformer = context.Context.RequestServices.GetRequiredService<IClaimsTransformer>();
            return await transformer.TransformAsync(context);
        });

        app.UseStatusCodePages();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
public class ClaimsTransformer : IClaimsTransformer
{
    private readonly IntranetContext dbcontext;

    /// <summary>
    /// Initializes a new instance of the <see cref="ClaimsTransformer" /> class.
    /// </summary>
    /// <param name="context">Also to be written.</param>
    public ClaimsTransformer(IntranetContext context)
    {
        this.dbcontext = context;
    }

    /// <summary>
    /// Manages claims against the ClaimsPrincipal for Authenticated Users
    /// </summary>
    /// <param name="context">Also to be written.</param>
    /// <returns>Still to be written.</returns>
    public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
        System.Security.Principal.WindowsIdentity windowsIdentity = null;

        foreach (var i in context.Principal.Identities)
        {
            if (i.GetType() == typeof(System.Security.Principal.WindowsIdentity))
            {
                windowsIdentity = (System.Security.Principal.WindowsIdentity)i;
            }
        }

        if (windowsIdentity != null)
        {
            var username = windowsIdentity.Name.Remove(0, 6);
            var appUser = this.dbcontext.Person.FirstOrDefault(m => m.Username == username);

            if (appUser != null)
            {
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Id", Convert.ToString(appUser.Id), ClaimValueTypes.Integer));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Fullname", appUser.Firstname + ' ' + appUser.Surname, ClaimValueTypes.String));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Firstname", appUser.Firstname, ClaimValueTypes.String));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Surname", appUser.Surname, ClaimValueTypes.String));

                if (appUser.Administrator)
                {
                    ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Administrator", "1", ClaimValueTypes.Boolean));
                }
            }
            else
            {
                Person newPerson = new Person();
                newPerson.Username = username;
                newPerson.Firstname = username.Split('.')[0].ToString().ToTitleCase();
                newPerson.Surname = username.Split('.')[1].ToString().ToTitleCase();
                newPerson.LocationId = 1;
                newPerson.CreatedBy = 1;
                newPerson.CreatedDate = DateTime.Now;
                newPerson.Email = username + "@mycompany.com";
                this.dbcontext.Add(newPerson);
                await this.dbcontext.SaveChangesAsync();

                appUser = this.dbcontext.Person.FirstOrDefault(m => m.Username == username);
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Id", Convert.ToString(appUser.Id), ClaimValueTypes.Integer));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Fullname", appUser.Firstname + ' ' + appUser.Surname, ClaimValueTypes.String));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Firstname", appUser.Firstname, ClaimValueTypes.String));
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Surname", appUser.Surname, ClaimValueTypes.String));
            }
        }

        return await System.Threading.Tasks.Task.FromResult(context.Principal);
    }
}
public类claimtransformer:IClaimsTransformer
{
私有只读IntranetContext dbcontext;
/// 
///初始化类的新实例。
/// 
///也要写。
公共索赔转换程序(IntranetContext上下文)
{
this.dbcontext=context;
}
/// 
///为经过身份验证的用户管理针对ClaimsPrincipal的索赔
/// 
///也要写。
///还有待写。
公共异步任务TransformAsync(ClaimTransformationContext)
{
System.Security.Principal.WindowsIdentity WindowsIdentity=null;
foreach(context.Principal.identifies中的var i)
{
if(i.GetType()==typeof(System.Security.Principal.WindowsIdentity))
{
windowsIdentity=(System.Security.Principal.windowsIdentity)i;
}
}
如果(windowsIdentity!=null)
{
var username=windowsIdentity.Name.Remove(0,6);
var appUser=this.dbcontext.Person.FirstOrDefault(m=>m.Username==Username);
if(appUser!=null)
{
((ClaimsIdentity)context.Principal.Identity).AddClaim(新声明(“Id”,Convert.ToString(appUser.Id),ClaimValueTypes.Integer));
((ClaimsIdentity)context.Principal.Identity).AddClaim(新声明(“全名”,appUser.Firstname+“”+appUser.姓氏,ClaimValueTypes.String));
((ClaimsIdentity)context.Principal.Identity).AddClaim(新的Claim(“Firstname”,appUser.Firstname,ClaimValueTypes.String));
((索赔实体)上下文