Расширение Iprincipal Точно.Метод isinrole()


В моем случае, мне нужно, чтобы дать роли для пользователей, но для конкретных подразделений, и я не хочу, чтобы реализовать новый механизм авторизации, который потребует, чтобы я доступ к БД каждый раз, когда я хочу проверить, если пользователь авторизован для определенной роли в определенном отделе.

Так я думал, я буду просто создать метод расширения IsInRole с двумя параметрами (role, departmentId). Вот точный код:

public static bool IsInRole(this IPrincipal principal, string role, int departmentId)
{
    var ident = principal?.Identity;
    if (ident == null)
        return false;

    if (departmentId <= 0)
        return false;

    var roleDeparments = ((ClaimsIdentity)ident).FindFirst($"{role} departments")?.Value;
    if (string.IsNullOrWhiteSpace(roleDeparments))
        return false;

    var inInRole = roleDeparments
        .Split(',')
        .Any(d => d == departmentId.ToString() || d == "all");

    return inInRole;
}

Роли пользователя сохраняются в БД и выбираются один раз при входе в систему, если departmentId установлено значение NULL, то это означает, что данная роль является общей для всех подразделений. Объект идентичности создается во время входа в систему, используя следующий метод:

private ClaimsIdentity CreateIdentity(User user)
{
    var identity = new ClaimsIdentity(MyAuthentication.ApplicationCookie, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
    identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "Active Directory"));
    identity.AddClaim(new Claim(ClaimTypes.Name, user.Id));
    identity.AddClaim(new Claim(ClaimTypes.GivenName, user.Name));
    identity.AddClaim(new Claim("DepartmentId", user.DepartmentId.ToString()));

    var roles = user.UserRoles
        .GroupBy(r => r.Role);

    foreach (var role in roles)
    {
        var departments = role
            .Select(r => r.DepartmentId)
            .Distinct()
            .ToList();

        bool isAll = departments.Any(d => d == null);

        string departmentIds = isAll
            ? "all"
            : string.Join(",", departments);

        identity.AddClaim(new Claim($"{role.Key.Name} departments", departmentIds));
    }

    return identity;
}

Теперь, я могу просто сделать что-то вроде:

if (User.IsInRole("schedule viewer", 2))
{
   .....
}

Это правильный подход?



1292
5
задан 27 февраля 2018 в 10:02 Источник Поделиться
Комментарии
1 ответ

Метод isinrole()

Мне не нравится, как параметры метода не подтверждена. ИМО нулевое распространение оператор не должен использоваться для всего, потому что это уменьшает читаемость. Имея нулевое распространения оператора "благополучно" "доступ" в собственность в порядке, если объект является первым по правую руку задание, как в Проверка var ident = principal?.Identity; но тем не менее я лично буду придерживаться совмещенный нулевой чек как так

if (principal == null || principal.Identity == null) { return false; }  

Но почему ты проверяешь это в начале метода ? Я хотел бы проверить простые типы бы departmentId <= 0.

Нулевая распространения здесь оператор

var roleDeparments = ((ClaimsIdentity)ident).FindFirst($"{role} departments")?.Value;  

могут быть пропущены на первый взгляд сопровождающего кода интересно, что это, по крайней мере, если он/она не в том, что хорошие глаза, как у меня. Он/она не может понять на первый взгляд, что вы "благополучно" доступ Value собственность здесь.

Можете ли вы найти здесь ошибку ?

var inInRole = roleDeparments
.Split(',')
.Any(d => d == departmentId.ToString() || d == "all");

Помимо орфографических ошибок в inInRole вы могли бы сохранить результат departmentId.ToString() в переменной для проверки в Any()но, может быть, компилятор достаточно умен, чтобы сделать это для вас.

Опуская скобки {} для одной линии if statemenst ваша ответственность. Я не буду этого делать. Если я сделаю это, то только как if (departmentId <= 0) return false;

Использование сокращений приводит к менее читабельный код. Почему бы вам не переименовать ident для identity ?

Реализация указанных точек приводит к

public static bool IsInRole(this IPrincipal principal, string role, int departmentId)
{
if (departmentId <= 0) { return false; }
if (principal == null || principal.Identity == null) { return false; }

var identity = principal.Identity;

var claim = ((ClaimsIdentity)identity).FindFirst($"{role} departments");
if (claim == null) { return false; }

var roleDeparments = claim.Value;
if (string.IsNullOrWhiteSpace(roleDeparments)) { return false; }

var isInRole = roleDeparments
.Split(',')
.Any(d => d == departmentId.ToString() || d == "all");

return isInRole;
}


Атрибут createidentity()

Это заставило меня задуматься

bool isAll = departments.Any(d => d == null);  

чтение isAll и Any. Перечитав свой вопрос, я споткнулся


если столбец DepartmentID установлено значение NULL, то это означает, что данная роль является общей для всех подразделений

Это кричали на комментарий, потому что мейнтейнер код должны знать это также. Вместе с лучшего названия было бы понятно для сопровождающего, что здесь происходит, как так

// If one of the user.UserRoles has a DepartmentId which is null,
// the role is general for all departments
bool isGeneralForAllDepartments = departments.Any(d => d == null);

string departmentIds = isGeneralForAllDepartments
? "all"
: string.Join(",", departments);

4
ответ дан 28 февраля 2018 в 07:02 Источник Поделиться