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

时间:2016-03-17 18:49:19

标签: authentication asp.net-core-mvc

我想用ASP.Net MVC 6

创建一个Intranet应用程序

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

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

    // GET: TestingAuths
    [Authorize(Roles ="administrator")]
    public IActionResult Index()
    {
        return View(_context.MyTestingAuth.ToList());
    }

如何检查登录的用户是否具有我的数据库角色表中的管理员角色。 这是一个解决方案,但它不适用于ASP.Net MVC 6:http://kitsula.com/Article/Custom-Role-Provider-for-MVC

我想要一个ASP.Net MVC 6的解决方案

3 个答案:

答案 0 :(得分:1)

我想你现在已经有了这个工作但我正在学习MVC和.Net Core我正在研究Intranet我使用了依赖于针对Person的数据库值的基于声明的授权。

我这样接近它,毫无疑问可以改进,但希望能及时到来。

<强> 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?}");
        });
    }

<强> ClaimsTransformer.cs

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);
    }
}
  

在任何控制器上我都可以申请[授权(政策=“管理员”)]

我希望这适合你。

感谢。

答案 1 :(得分:0)

理想情况下,您的身份/身份验证提供程序会在声明标识中提供角色声明(如果您的控件中有此声明)

但是,另一种方法是编写自己的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();
    }
}

并注册:

var defaultPolicy = new AuthorizationPolicyBuilder().AddRequirements(new CustomAuthorizationRequirement ()).Build();
var mvcBuilder = services.AddMvcCore(options => options.Filters.Add(new AuthorizeFilter(defaultPolicy)));

答案 2 :(得分:-2)

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

需求的处理程序可以在其构造函数中使用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);
        }
    }
}

然后,您只需在ConfigureServices()中的startup.cs中配置策略和处理程序,并记住在DI系统中注册您的角色存储库,然后就可以了。

这可能看起来像

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

services.AddSingleton<IAuthorizationHandler, MyRolesAuthorizationHandler>();

Code based policiesDI in handlers

一样在文档中

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