Nếu API web của bạn chỉ được sử dụng trong một ứng dụng MVC hiện có, lời khuyên của tôi là tạo ra một bộ lọc tùy chỉnh AuthorizeAttribute
cho cả MVC và WebAPI điều khiển của bạn; Tôi tạo bộ lọc "AuthorizeSafe", mặc định sẽ liệt kê mọi thứ theo mặc định để nếu bạn quên áp dụng thuộc tính ủy quyền cho bộ điều khiển hoặc phương pháp, bạn bị từ chối truy cập (tôi nghĩ rằng cách tiếp cận danh sách trắng mặc định không an toàn).
Hai lớp thuộc tính được cung cấp để bạn mở rộng; System.Web.Mvc.AuthorizeAttribute
và System.Web.Http.AuthorizeAttribute
; trước đây được sử dụng với xác thực biểu mẫu MVC và sau này cũng móc vào xác thực biểu mẫu (điều này rất hay vì nó có nghĩa là bạn không phải xây dựng một kiến trúc xác thực hoàn toàn riêng biệt để xác thực và ủy quyền API của bạn). Dưới đây là những gì tôi đã đưa ra - nó từ chối truy cập vào tất cả các bộ điều khiển/hành động MVC và các bộ điều khiển/hành động WebApi theo mặc định trừ khi áp dụng thuộc tính AllowAnonymous
hoặc AuthorizeSafe
. Thứ nhất, một phương pháp khuyến nông để giúp đỡ với tùy chỉnh thuộc tính:
public static class CustomAttributeProviderExtensions {
public static List<T> GetCustomAttributes<T>(this ICustomAttributeProvider provider, bool inherit) where T : Attribute {
List<T> attrs = new List<T>();
foreach (object attr in provider.GetCustomAttributes(typeof(T), false)) {
if (attr is T) {
attrs.Add(attr as T);
}
}
return attrs;
}
}
Lớp uỷ quyền helper rằng cả AuthorizeAttribute
mở rộng sử dụng:
public static class AuthorizeSafeHelper {
public static AuthActionToTake DoSafeAuthorization(bool anyAllowAnonymousOnAction, bool anyAllowAnonymousOnController, List<AuthorizeSafeAttribute> authorizeSafeOnAction, List<AuthorizeSafeAttribute> authorizeSafeOnController, out string rolesString) {
rolesString = null;
// If AllowAnonymousAttribute applied to action or controller, skip authorization
if (anyAllowAnonymousOnAction || anyAllowAnonymousOnController) {
return AuthActionToTake.SkipAuthorization;
}
bool foundRoles = false;
if (authorizeSafeOnAction.Count > 0) {
AuthorizeSafeAttribute foundAttr = (AuthorizeSafeAttribute)(authorizeSafeOnAction.First());
foundRoles = true;
rolesString = foundAttr.Roles;
}
else if (authorizeSafeOnController.Count > 0) {
AuthorizeSafeAttribute foundAttr = (AuthorizeSafeAttribute)(authorizeSafeOnController.First());
foundRoles = true;
rolesString = foundAttr.Roles;
}
if (foundRoles && !string.IsNullOrWhiteSpace(rolesString)) {
// Found valid roles string; use it as our own Roles property and auth normally
return AuthActionToTake.NormalAuthorization;
}
else {
// Didn't find valid roles string; DENY all access by default
return AuthActionToTake.Unauthorized;
}
}
}
public enum AuthActionToTake {
SkipAuthorization,
NormalAuthorization,
Unauthorized,
}
Hai lớp học mở rộng bản thân:
public sealed class AuthorizeSafeFilter : System.Web.Mvc.AuthorizeAttribute {
public override void OnAuthorization(AuthorizationContext filterContext) {
if (!string.IsNullOrEmpty(this.Roles) || !string.IsNullOrEmpty(this.Users)) {
throw new Exception("This class is intended to be applied to an MVC web API application as a global filter in RegisterWebApiFilters, not applied to individual actions/controllers. Use the AuthorizeSafeAttribute with individual actions/controllers.");
}
string rolesString;
AuthActionToTake action = AuthorizeSafeHelper.DoSafeAuthorization(
filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(false).Count() > 0,
filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(false).Count() > 0,
filterContext.ActionDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>(false),
filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>(false),
out rolesString
);
string rolesBackup = this.Roles;
try {
switch (action) {
case AuthActionToTake.SkipAuthorization:
return;
case AuthActionToTake.NormalAuthorization:
this.Roles = rolesString;
base.OnAuthorization(filterContext);
return;
case AuthActionToTake.Unauthorized:
filterContext.Result = new HttpUnauthorizedResult();
return;
}
}
finally {
this.Roles = rolesBackup;
}
}
}
public sealed class AuthorizeSafeApiFilter : System.Web.Http.AuthorizeAttribute {
public override void OnAuthorization(HttpActionContext actionContext) {
if (!string.IsNullOrEmpty(this.Roles) || !string.IsNullOrEmpty(this.Users)) {
throw new Exception("This class is intended to be applied to an MVC web API application as a global filter in RegisterWebApiFilters, not applied to individual actions/controllers. Use the AuthorizeSafeAttribute with individual actions/controllers.");
}
string rolesString;
AuthActionToTake action = AuthorizeSafeHelper.DoSafeAuthorization(
actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0,
actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0,
actionContext.ActionDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>().ToList(),
actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>().ToList(),
out rolesString
);
string rolesBackup = this.Roles;
try {
switch (action) {
case AuthActionToTake.SkipAuthorization:
return;
case AuthActionToTake.NormalAuthorization:
this.Roles = rolesString;
base.OnAuthorization(actionContext);
return;
case AuthActionToTake.Unauthorized:
HttpRequestMessage request = actionContext.Request;
actionContext.Response = request.CreateResponse(HttpStatusCode.Unauthorized);
return;
}
}
finally {
this.Roles = rolesBackup;
}
}
}
Và cuối cùng, thuộc tính có thể được áp dụng cho các phương thức/bộ điều khiển để cho phép người dùng trong một số vai trò nhất định truy cập chúng:
public class AuthorizeSafeAttribute : Attribute {
public string Roles { get; set; }
}
Sau đó, chúng tôi đăng ký "AuthorizeSafe" của chúng tôi trên toàn cầu bộ lọc từ Global.asax:
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
// Make everything require authorization by default (whitelist approach)
filters.Add(new AuthorizeSafeFilter());
}
public static void RegisterWebApiFilters(HttpFilterCollection filters) {
// Make everything require authorization by default (whitelist approach)
filters.Add(new AuthorizeSafeApiFilter());
}
Sau đó, để mở ra một hành động để ví dụ.truy cập vô danh hoặc chỉ truy cập Quản trị viên:
public class AccountController : System.Web.Mvc.Controller {
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl) {
// ...
}
}
public class TestApiController : System.Web.Http.ApiController {
// GET API/TestApi
[AuthorizeSafe(Roles="Admin")]
public IEnumerable<TestModel> Get() {
return new TestModel[] {
new TestModel { TestId = 123, TestValue = "Model for ID 123" },
new TestModel { TestId = 234, TestValue = "Model for ID 234" },
new TestModel { TestId = 345, TestValue = "Model for ID 345" }
};
}
}
Chia sẻ một số cấu hình, mã ... – Aliostad