Tôi thực hiện xác thực mô hình trong bộ điều khiển của mình, nhưng việc xác thực doanh nghiệp thứ hai cần phải diễn ra ở cấp dịch vụ/doanh nghiệp. Điều này thường liên quan đến quyền của người dùng: người dùng hiện tại có quyền truy cập vào thông tin khách hàng/đơn đặt hàng mà anh đang cố gắng nhận hoặc đăng không?Bao gồm người dùng hiện tại vào mọi cuộc gọi đến lớp dịch vụ từ bộ điều khiển
Cách tiếp cận đầu tiên (và làm việc) của tôi là vượt qua toàn bộ trường hợp User
hoặc Id
(bằng cách gọi User.Identity.GetUserId()
), điều này sẽ là đủ nhất - không phải tất cả thời gian. Vì vậy, tôi sẽ có một cái gì đó như thế này:
public IHttpActionResult Get(int id)
{
try
{
var customer = customerService.GetById(id, userId);
return Ok(customer);
}
catch (BusinessLogicException e)
{
return CreateErrorResponse(e);
}
}
Nhưng tôi không thực sự thích thực tế là với cách tiếp cận này tôi sẽ phải bao gồm một tham số thêm trong mọi cuộc gọi đến lớp dịch vụ của tôi. Nếu tôi đang gọi phương thức GetById()
, tôi muốn nhận một cái gì đó bằng cách cung cấp ID, không phải ID người dùng ID và ID người dùng.
Một cách giải quyết đơn giản sẽ là một cái gì đó dọc theo những dòng này, mà cũng làm việc:
public IHttpActionResult Get(int id)
{
customerService.SetCurrentUser(User.Identity.GetUserId());
try
{
var customer = customerService.GetById(id);
return Ok(customer);
}
catch (BusinessLogicException e)
{
return CreateErrorResponse(e);
}
}
Nhưng thay vì phải thực hiện cuộc gọi riêng biệt để thiết lập người dùng hiện tại, tôi muốn điều này được thực hiện tự động với mọi cuộc gọi đến dịch vụ. Tôi làm nó như thế nào?
Đây là những gì dịch vụ của tôi trông giống như:
public class CustomerService : EntityService<Customer>, ICustomerService
{
public string UserId;
IContext context;
public CustomerService(IContext context) : base(context)
{
this.context = context;
this.dbSet = context.Set<Customer>();
}
public void SetCurrentUser(string userId)
{
UserId = userId;
}
public DTO.Customer GetById(int id)
{
if (!IsAccessibleByUser(id))
{
throw new BusinessLogicException(ErrorCode.UserError, "UserId: " + UserId);
}
return dbSet.FirstOrDefault(x => x.Id == id).ToDto<Customer, DTO.Customer>();
}
public bool IsAccessibleByUser(int id)
{
return context.UsersAPI.Any(a => a.AspNetUsersID == UserId);
}
}
Tôi đã sử dụng một 'CustomAuthorizeAttribute' để trả về một thông báo lỗi cụ thể trong trường hợp các mã thông báo là không hợp lệ hoặc người dùng không có vai trò cần thiết. Cách tiếp cận này có vẻ rất thú vị vì nó sẽ loại bỏ một * tấn * logic xác nhận trong lớp logic nghiệp vụ của tôi, nhưng nó cảm thấy hơi lạ khi có nhiều logic xác nhận ở đâu đó trong ứng dụng của tôi. Ngoài ra, bạn có thể mở rộng đoạn cuối của mình không? Tiêm bối cảnh dữ liệu của tôi (dịch vụ của tôi, trong trường hợp này) vào bộ lọc ủy quyền có vẻ như một vấn đề khác mà tôi cần phải giải quyết để sử dụng phương pháp này. – Antrim
Như tôi đã nêu trong câu trả lời của tôi nếu bạn cần tiêm phụ thuộc, tất cả những gì bạn cần sử dụng là một nhà cung cấp bộ lọc tùy chỉnh. Vì vậy, sau một số tìm kiếm bạn có thể tìm thấy: http://haacked.com/archive/2011/04/25/conditional-filters.aspx/ Thuộc tính điểm đánh dấu trên các hành động của trình điều khiển có thể cho phép bạn phát hiện trong nhà cung cấp bộ lọc tùy chỉnh nếu bạn cần để áp dụng logic ủy quyền. Và bạn nên tự hỏi mình: Tôi có đang sử dụng lớp kinh doanh này * ở bất cứ đâu ngoài ứng dụng MVC mà tôi nên quan tâm không? Nếu có lẽ lớp kinh doanh này đã được bọc phía sau một mặt tiền RESTful. –
Vì vậy, không chỉ cần chờ đợi tôi viết tất cả các mã cho bạn, nhìn xung quanh, thử nghiệm, trở lại với các câu hỏi cụ thể nếu bạn có như vậy. –