Мелкозернистые разрешения; PrincipalPermission - роли, отделенные от разрешений;
Я некоторое время использовал PrincipalPermission в сервисах wcf. [PrincipalPermission(SecurityAction.Demand, Role = SecurityRoles.CanManageUsers)]
Наши роли имеют префикс: Can* и это то, как мы добиваемся тонкого контроля действий с помощью встроенной системы членства asp.net.
Это затрудняет понимание как бизнес-единицы, какие тонко детализированные роли мы можем дать пользователю.
Вот мой новый подход, и я хотел посмотреть, сможет ли кто-нибудь дать отзыв, пересмотреть код, прежде чем я реализую свое предложение.
1) aspnet_roles - роль бизнес-единицы
2) Расширить систему членства asp.net, создав таблицу разрешений и таблицу Role_Permission и таблицу User_Permission (многие ко многим)
3) создать пользовательский CodeAccessSecurityAttribute +, который просматривает новые таблицы [CustomPermissionCheck(Security.Demand, HasPermission="can*")] первая итерация, я статически создаю новый зависимый репозиторий.. в идеале я хотел бы, чтобы атрибут стиля aop вставлял репозиторий IPermissionRepository.HasPermission(...);
Если я подойду по-новому, я, вероятно, перестану наследовать от CodeAccessSecurityAttribute - что по этому поводу скажут парни из службы безопасности?
кто-нибудь еще решил это, есть что-то в рамках, что я пропустил?
2 ответа
Я реализовал первую итерацию, и она работает хорошо. [PermissionValidate(SecurityAction.Demand, HasPermission = CensusSchedulerRoles.CanUpdateCensusScheduler)]
public void Demand()
{
var principal = Thread.CurrentPrincipal;
if(principal == null || principal.Identity.IsAuthenticated == false)
{
throw new SecurityException("Unable to get IPrincipal.");
}
if(principal.Identity.IsAuthenticated == false)
{
throw new SecurityException("You must be authenticated.");
}
#warning this should be moved to an aop attribute that is injected by a ioc container.
using (var connection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["......."].ConnectionString))
{
connection.Open();
using(var command = new SqlCommand(
@"
SELECT COUNT(t.name) FROM
(
SELECT p.name, u.UserName FROM
aspnet_Users as u
INNER JOIN [User_Permission] as up
ON up.user_id = u.UserId
INNER JOIN Permission as p
ON p.id = up.permission_id
UNION
SELECT p2.name, u2.UserName FROM
aspnet_Users as u2
INNER JOIN aspnet_UsersInRoles as uir
ON uir.UserId = u2.UserId
INNER JOIN aspnet_Roles as r
ON r.RoleId = uir.RoleId
INNER JOIN Role_Permission as rp
ON rp.role_id = r.RoleId
INNER JOIN Permission as p2
ON p2.id = rp.permission_id
) as t
WHERE t.UserName = @username AND t.name = @haspermission
", connection))
{
command.Parameters.Add("@username", SqlDbType.VarChar).Value = Thread.CurrentPrincipal.Identity.Name;
command.Parameters.Add("@haspermission", SqlDbType.VarChar).Value = _permissionRequested;
if( Convert.ToInt32(command.ExecuteScalar()) <=0)
{
throw new SecurityException(String.Format("User '{0}' is not assigned permission '{1}'.", principal.Identity.Name, _permissionRequested));
}
}
}
}
Я бы сказал, что если вы находитесь в ASP.NET, то вам следует реализовать собственный RoleProvider.
В вашем пользовательском RoleProvider вы получите доступ к другой таблице, в которой бизнес-группы будут связаны с детализированными разрешениями.
Затем, когда вы узнаете пользователя, вы можете выяснить, в какой бизнес-группе он находится, и назначить все соответствующие роли в RoleProvider, а не изменять имеющийся у вас код.
Это также работает лучше, потому что позволяет легко изменять какие группы имеют какие разрешения, сохраняя при этом модель домена для разрешений чисто на стороне кода.