refine role auth

This commit is contained in:
Jicheng Lu 2024-11-14 20:19:53 -06:00
parent dda5c2a211
commit 39862dfab6
8 changed files with 60 additions and 52 deletions

View file

@ -10,7 +10,7 @@ public interface IUserService
Task<PagedItems<User>> GetUsers(UserFilter filter);
Task<User?> GetUserDetails(string userId);
Task<bool> IsAuthorizedUser(string userId);
Task<UserAuthorization> GetUserAuthorizations(string? agentId = null);
Task<UserAuthorization> GetUserAuthorizations(IEnumerable<string>? agentIds = null);
Task<bool> UpdateUser(User user, bool isUpdateUserAgents = false);
Task<User> CreateUser(User user);
Task<Token> ActiveUser(UserActivationModel model);

View file

@ -4,5 +4,22 @@ public class UserAuthorization
{
public bool IsAdmin { get; set; }
public IEnumerable<string> Permissions { get; set; } = [];
public IEnumerable<string> AgentActions { get; set; } = [];
public IEnumerable<UserAgent> AgentActions { get; set; } = [];
}
public static class UserAuthorizationExtension
{
public static bool IsAgentActionAllowed(this UserAuthorization auth, string agentId, string targetAction)
{
if (auth == null || string.IsNullOrEmpty(agentId)) return false;
if (auth.IsAdmin) return true;
var found = auth.AgentActions.FirstOrDefault(x => x.AgentId == agentId);
if (found == null) return false;
var actions = found.Actions ?? [];
return actions.Any(x => x == targetAction);
}
}

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Abstraction.Users.Models;
namespace BotSharp.Core.Agents.Services;
@ -7,9 +8,9 @@ public partial class AgentService
public async Task<bool> DeleteAgent(string id)
{
var userService = _services.GetRequiredService<IUserService>();
var auth = await userService.GetUserAuthorizations(id);
var auth = await userService.GetUserAuthorizations(new List<string> { id });
if (auth.IsAdmin || auth.AgentActions.Contains(UserAction.Edit))
if (!auth.IsAgentActionAllowed(id, UserAction.Edit))
{
return false;
}

View file

@ -1,6 +1,7 @@
using BotSharp.Abstraction.Repositories.Enums;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Abstraction.Users.Models;
using System.IO;
namespace BotSharp.Core.Agents.Services;
@ -12,9 +13,10 @@ public partial class AgentService
if (agent == null || string.IsNullOrEmpty(agent.Id)) return;
var userService = _services.GetRequiredService<IUserService>();
var auth = await userService.GetUserAuthorizations(agent.Id);
var auth = await userService.GetUserAuthorizations(new List<string> { agent.Id });
var allowEdit = auth.IsAgentActionAllowed(agent.Id, UserAction.Edit);
if (!auth.IsAdmin && !auth.AgentActions.Contains(UserAction.Edit))
if (!allowEdit)
{
return;
}

View file

@ -414,7 +414,7 @@ public class UserService : IUserService
return user != null && UserConstant.AdminRoles.Contains(user.Role);
}
public async Task<UserAuthorization> GetUserAuthorizations(string? agentId = null)
public async Task<UserAuthorization> GetUserAuthorizations(IEnumerable<string>? agentIds = null)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var user = db.GetUserById(_user.Id);
@ -422,32 +422,33 @@ public class UserService : IUserService
if (user == null) return auth;
var permissions = user.Permissions;
var role = db.GetRoles(new RoleFilter { Names = [ user.Role ] }).FirstOrDefault();
if (role != null && !permissions.Any())
{
permissions = role.Permissions ?? [];
}
auth.IsAdmin = UserConstant.AdminRoles.Contains(user.Role);
var role = db.GetRoles(new RoleFilter { Names = [user.Role] }).FirstOrDefault();
var permissions = user.Permissions?.Any() == true ? user.Permissions : role?.Permissions ?? [];
auth.Permissions = permissions;
if (string.IsNullOrEmpty(agentId))
if (agentIds == null || !agentIds.Any())
{
return auth;
}
var userAgent = db.GetUserDetails(user.Id)?.AgentActions?.FirstOrDefault(x => x.AgentId == agentId);
var actions = userAgent?.Actions ?? [];
var userAgents = db.GetUserDetails(user.Id)?.AgentActions?
.Where(x => agentIds.Contains(x.AgentId) && x.Actions.Any())?.Select(x => new UserAgent
{
AgentId = x.AgentId,
Actions = x.Actions
}).ToList() ?? [];
if (role != null && !actions.Any())
{
var roleAgent = db.GetRoleDetails(role.Id)?.AgentActions?.FirstOrDefault(x => x.AgentId == agentId);
actions = roleAgent?.Actions ?? [];
}
var userAgentIds = userAgents.Select(x => x.AgentId).ToList();
var roleAgents = db.GetRoleDetails(role?.Id)?.AgentActions?
.Where(x => !userAgentIds.Contains(x.AgentId))?.Select(x => new UserAgent
{
AgentId = x.AgentId,
Actions = x.Actions
})?.ToList() ?? [];
auth.AgentActions = actions;
auth.AgentActions = userAgents.Concat(roleAgents);
return auth;
}

View file

@ -1,4 +1,3 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Users.Enums;
namespace BotSharp.OpenAPI.Controllers;
@ -59,10 +58,12 @@ public class AgentController : ControllerBase
}
var userService = _services.GetRequiredService<IUserService>();
var auth = await userService.GetUserAuthorizations(targetAgent.Id);
var auth = await userService.GetUserAuthorizations(new List<string> { targetAgent.Id });
targetAgent.Editable = auth.IsAdmin || auth.AgentActions.Contains(UserAction.Edit);
targetAgent.Chatable = auth.IsAdmin || auth.AgentActions.Contains(UserAction.Chat);
targetAgent.Editable = auth.IsAgentActionAllowed(targetAgent.Id, UserAction.Edit);
targetAgent.Chatable = auth.IsAgentActionAllowed(targetAgent.Id, UserAction.Chat);
targetAgent.Trainable = auth.IsAgentActionAllowed(targetAgent.Id, UserAction.Train);
targetAgent.Evaluable = auth.IsAgentActionAllowed(targetAgent.Id, UserAction.Evaluate);
return targetAgent;
}
@ -85,27 +86,14 @@ public class AgentController : ControllerBase
};
}
var userAgents = new List<UserAgent>();
var user = await userService.GetUser(_user.Id);
if (!UserConstant.AdminRoles.Contains(user.Role))
{
userAgents = await _agentService.GetUserAgents(user.Id);
}
var auth = await userService.GetUserAuthorizations(pagedAgents.Items.Select(x => x.Id));
agents = pagedAgents?.Items?.Select(x =>
{
var chatable = true;
var editable = true;
if (!UserConstant.AdminRoles.Contains(user.Role))
{
var actions = userAgents.FirstOrDefault(a => a.AgentId == x.Id)?.Actions ?? [];
chatable = actions.Contains(UserAction.Chat);
editable = actions.Contains(UserAction.Edit);
}
var model = AgentViewModel.FromAgent(x);
model.Editable = editable;
model.Chatable = chatable;
model.Editable = auth.IsAgentActionAllowed(x.Id, UserAction.Edit);
model.Chatable = auth.IsAgentActionAllowed(x.Id, UserAction.Chat);
model.Trainable = auth.IsAgentActionAllowed(x.Id, UserAction.Train);
model.Evaluable = auth.IsAgentActionAllowed(x.Id, UserAction.Evaluate);
return model;
})?.ToList() ?? [];

View file

@ -48,6 +48,8 @@ public class AgentViewModel
public bool Editable { get; set; }
public bool Chatable { get; set; }
public bool Trainable { get; set; }
public bool Evaluable { get; set; }
[JsonPropertyName("created_datetime")]
public DateTime CreatedDateTime { get; set; }

View file

@ -43,22 +43,19 @@ public partial class MongoRepository
public User? GetUserById(string id)
{
var user = _dc.Users.AsQueryable()
.FirstOrDefault(x => x.Id == id || (x.ExternalId != null && x.ExternalId == id));
var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.Id == id || (x.ExternalId != null && x.ExternalId == id));
return user != null ? user.ToUser() : null;
}
public List<User> GetUserByIds(List<string> ids)
{
var users = _dc.Users.AsQueryable()
.Where(x => ids.Contains(x.Id) || (x.ExternalId != null && ids.Contains(x.ExternalId))).ToList();
var users = _dc.Users.AsQueryable().Where(x => ids.Contains(x.Id) || (x.ExternalId != null && ids.Contains(x.ExternalId))).ToList();
return users?.Any() == true ? users.Select(x => x.ToUser()).ToList() : new List<User>();
}
public List<User> GetUsersByAffiliateId(string affiliateId)
{
var users = _dc.Users.AsQueryable()
.Where(x => x.AffiliateId == affiliateId).ToList();
var users = _dc.Users.AsQueryable().Where(x => x.AffiliateId == affiliateId).ToList();
return users?.Any() == true ? users.Select(x => x.ToUser()).ToList() : new List<User>();
}