2016-03-17 33 views
0

檢查我想創建一個與ASP.Net MVC 6ASP.Net MVC 6 Windows身份驗證自定義授權自定義角色從數據庫

我使用Windows身份驗證的Intranet應用我想從數據庫表

根據設定不同的規則

例如,如果我想限制從函數或控制器

// 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

回答

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))); 
+0

可以添加更多的信息我如何檢查來自數據庫授權過濾器或從數據庫 –

+0

角色,你如何排序/管理用戶/角色模型是由你.....但我已經添加了一個編輯來顯示這 –

+0

粗糙例子你能給一步一步的例子,我是新 –

-2

而不是做一個角色檢查,你應該看看代碼政策。

需求處理程序可以在其構造函數中使用DI元素,因此您可以將您的RoleRepository註冊到DI中,然後將其放入處理程序構造函數中。然後使用參數化要求來配置您的策略。

因此,例如;

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 policies在文檔中的是DI in handlers

請注意,此代碼是在輸入框中,而不是VS這樣做也可能無法編譯:)

+0

親愛Blowdart,可以請您給步步詳細例如,由於我是新來這個 –

+0

爲什麼這個downvoted這麼多? –

+0

嗯,這是正確的,只要它去,但(一)它無法解釋_why_你不應該做一個角色檢查_ [真的,爲什麼我們_have_角色,並修改它們沒有明顯的方法?] _,和( b)它不一致地使用'MyRole'和'MyRoles',所以它顯然不是實際測試的代碼。 @blowdart在其他地方更好地解釋了這一切,但花了我數天的時間才找到。 – Auspex

1

我想你現在有這樣的工作,但對於我在學習MVC和.Net Core時所使用的Intranet,我使用了依賴於針對Person的數據庫值的基於聲明的授權。

我以這種方式接近它,這無疑可以改善,但希望能及時到達。

啓動。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); 
    } 
} 

在任何控制器我可以再申請[授權(策略= 「管理員」)

我希望作品爲你。

謝謝。

+0

這可以通過一些內嵌評論大大改善。 – Gusdor

+0

我會嘗試@Gusdor但作爲一個新手,我仍然不完全理解的一切會在這裏,它基於SO和MSDN的研究,特別是ASP網/核心網站,而編譯。 – K7Buoy

+0

沒有戲劇。我花了一些時間,對關鍵要素有一個粗略的概念。我會盡可能幫助。 – Gusdor