Подтвердить что ты не робот

Как получить роль пользователя внутри метода WebAPI без поиска таблицы AspNetUserRoles?

У меня есть хранимая процедура, которая обновляет статус. В зависимости от роли пользователя хранимая процедура имеет код, который может или не может позволить изменять статус. По этой причине мне нужно передать имя роли в хранимую процедуру. Имя моей роли хранится на клиенте в моем javascript-коде, но, конечно, мне нужна вторая проверка на сервере. Каждый пользователь имеет только одну из трех ролей и при запросе обновления статуса я могу вызвать один из трех методов в зависимости от роли, которую имеет клиент. Вот что я пробовал.

Я использую WebApi с аутентификацией на основе токена и идентификатором ASP.NET 2.1, и приложение всегда работает в браузере. Мои пользователи настроены с соответствующими ролями.

Я установил код, чтобы получить userId, а затем перейдите в таблицу AspNetUserRoles, чтобы получить роль в начале метода. Однако я заметил, что для этого требуется около 500 миллисекунд. В качестве альтернативы я рассматриваю следующее:

    [HttpPut]
    [Authorize(Roles = "Admin")]
    [Route("AdminUpdateStatus/{userTestId:int}/{userTestStatusId:int}")]
    public async Task<IHttpActionResult> AdminUpdateStatus(int userTestId, int userTestStatusId)
    {
        return await UpdateStatusMethod(userTestId, userTestStatusId, "Admin");
    }

    [HttpPut]
    [Authorize(Roles = "Student")]
    [Route("StudentUpdateStatus/{userTestId:int}/{userTestStatusId:int}")]
    public async Task<IHttpActionResult> StudentUpdateStatus(int userTestId, int userTestStatusId)
    {
        return await UpdateStatusMethod(userTestId, userTestStatusId, "Student");
    }

    [HttpPut]
    [Authorize(Roles = "Teacher")]
    [Route("TeacherUpdateStatus/{userTestId:int}/{userTestStatusId:int}")]
    public async Task<IHttpActionResult> TeacherUpdateStatus(int userTestId, int userTestStatusId)
    {
        return await UpdateStatusMethod(userTestId, userTestStatusId, "Teacher");
    }

    private async Task<IHttpActionResult> UpdateStatusMethod(int userTestId, int userTestStatusId, string roleName)
    {
        // Call the stored procedure here and pass in the roleName
    }

Это эффективный способ сделать это или есть еще один более чистый способ. То, что я довольно неясно, - это то, что передняя или задняя часть кэширует роль пользователей. Я предполагаю, что это сделано или есть некоторые настройки, которые позволят это сделать.

Примечание. Я использую утверждения для отправки информации о роли моему клиенту здесь:

public static AuthenticationProperties CreateProperties(
            string userName,
            ClaimsIdentity oAuthIdentity,
            string firstName,
            string lastName,
            int organization)
        {
            IDictionary<string, string> data = new Dictionary<string, string>
                {
                    { "userName", userName},
                    { "firstName", firstName},
                    { "lastName", lastName},
                    { "organization", organization.ToString()},
                    { "roles",string.Join(":",oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())}

                };
            return new AuthenticationProperties(data);
        }

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

Любая помощь и советы будут высоко оценены.

4b9b3361

Ответ 1

Как вы заявили, вы используете токены-носители для защиты своих конечных точек. Я считаю, что есть мало недоразумений в том, что в них содержатся магические струны-носители. Ну, эти жетоны содержат все роли для пользователя, которому вы выдали токен, а также если вы используете DPAPI по умолчанию для защиты данных в Web API не (JWT Tokens), то эти токены подписываются и шифруются, поэтому никто не может вмешиваться в данные внутри маркера, если у него нет машинного ключа для веб-сервера, выдавшего этот токен, поэтому не беспокойтесь о защите данных.

Моя рекомендация состоит в том, чтобы прочитать роли/претензии для пользователя из базы данных, нет необходимости в обходных методах и взломах, которые вы пытаетесь сделать, все, что вам нужно сделать, - это установить требования к пользователям при входе в систему в методе GrantResourceOwnerCredentials Вы можете установить его таким образом, получив пользователя, затем прочитав роли из БД и установив их в качестве утверждения типа "Роль"

 var identity = new ClaimsIdentity(context.Options.AuthenticationType);
 identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
 identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
 identity.AddClaim(new Claim(ClaimTypes.Role, "Supervisor"));

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

Или, если вы хотите создать личность из базы данных, вы можете использовать ниже:

 public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
        // Add custom user claims here
        return userIdentity;
    }

Затем в GrantResourceOwnerCredentials сделайте следующее:

ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType);

Теперь, как только вы отправите токен-носитель в защищенную конечную точку с помощью атрибута Authorize, например [Authorize(Roles = "Teacher")], я могу заверить вас, что ваш код не пойдет в БД, чтобы сделать какой-либо запрос открытым профилировщиком SQL и проверить, прочитает ли он заявки из зашифрованного токена вместе с требованием Роли и проверить, принадлежит ли этот пользователь роли Учителя и разрешить или отклонить запрос.

Я опубликовал подробную серию из 5 сообщений о аутентификации на основе токенов вместе с сервером авторизации, и токены JWT. Я рекомендую вам прочитать эти сообщения, чтобы лучше понять токены-носители.

Ответ 2

Вместо трех отдельных методов вы можете просто проверить User.IsInRole("RoleName"), доступные в классе контроллера. Он использует ту же логику, что и в атрибуте [Authorise]. например.

public class DataApiController : ApiController
{
    [HttpPut]
    [Route("UpdateStatus/{userTestId:int}/{userTestStatusId:int}")]
    public async Task<IHttpActionResult> UpdateStatus(int userTestId, int userTestStatusId)
    {
        if(User.IsInRole("Admin"))
        {
            //Update method etc....
        }
        //else if(....) else etc
    {
}

Ответ 3

Заявки о роли по умолчанию хранятся в файле cookie для входа пользователя, поэтому [Authorize (Роли = "Учитель" )] должен быть быстрым. Единственный бэнд базы данных будет при первом входе в систему (или при обновлении знака в cookie. Проверки авторизации выполняются против IClaimsPrincipal, созданных из знака в cookie.

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