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

Как отправить информацию о авторизации обратно в мое клиентское приложение, используя AngularJS, WebAPI 2 и Oauth 2?

У меня есть клиентское приложение AngularJS, которое использует javascript (не coffeescript или typescript) Oauth2 для проверки подлинности в приложении WebAPI 2 с использованием последней Identity 2. Все программное обеспечение в моем приложении является самым последним и основано на this example. Мои целевые клиенты браузера - IE9 и выше.

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

user.authenticate = function (userName, password, rememberMe, successCallback, errorCallback) {
    var config = {
        method: 'POST',
        url: '/Token',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        data: 'grant_type=password&username=' + encodeURIComponent(userName) + '&password=' + encodeURIComponent(password),
    };

Я разрабатываю VS2013 Update 2 и на сервере, я использую С#, последнюю Entity Framework и SQL Server 2012.

Для входа в систему мой клиент вызывает метод /Token в WebAPI и передает идентификатор пользователя и пароль. Затем WebAPI отвечает на токен клиенту, который я храню. С каждым запросом к WebAPI токен отправляется обратно и аутентифицируется:

$http.defaults.headers.common.Authorization = 'Bearer ' + user.data.bearerToken;

Это работает очень хорошо до сих пор, но, поскольку оно стоит, приложение не может сказать разницу между пользователями, которым назначены разные роли.

Некоторые из методов WebAPI могут выполняться только пользователями, которые имеют определенную роль. Я хотел бы настроить меню моего внешнего приложения AngularJS, чтобы только в том случае, если у пользователя есть эта роль, тогда соответствующие ссылки появятся видимыми. Я понимаю, что это не помешает пользователю проверять HTML и публикацию, но меня это не беспокоит, так как у меня все еще будет украшение методов, чтобы ограничить способность пользователей не выполнять роли.

Может ли кто-нибудь дать мне пример того, как я могу это сделать, используя только набор продуктов, упомянутых выше, которые я упоминаю в вопросе плюс JavaScript-токены, если они помогают обновить решение, Из того, что я понимаю, роли обрабатываются заявлениями, но я не понимаю, как их добавить и отправить их клиенту с помощью токенов. Я провел много исследований в Интернете, но мне не удалось найти хороших примеров, так как я думаю, что большинство из них очень новы, и не так много людей имели возможность изучить, как СПА может использовать это самое последнее программное обеспечение компоненты.

При ответе на этот вопрос обратите внимание на, что я не ищу ответа, который может сообщать сообществу, как настраивать роли на сервере или отвечать на них, объясняя, насколько важно предоставлять роль проверки на сервере. Я думаю, что почти все знают об этом. То, что я действительно считаю полезным, - это очень подробные технические рекомендации с примером кода и объяснением. Чтобы сфокусировать ответ, он, вероятно, будет полезен всем, если ответы, которые не отвечают этой потребности, не публикуются в качестве предлагаемых ответов.

Спасибо заранее.

4b9b3361

Ответ 1

Короткий ответ на ваш вопрос - метод ApplicationOAuthProvider.CreateProperties. Он создан для вас по умолчанию и находится в WebApi2/Provider/ApplicationOAuthProvider.cs. По умолчанию он отправляет только userName

//WepApi2/Providers/ApplicationOAuthProvider.cs
public static AuthenticationProperties CreateProperties(string userName)
{
    IDictionary<string, string> data = new Dictionary<string, string>
    {
        { "userName", userName }
    };
    return new AuthenticationProperties(data);
}

Я бы сделал следующее обновление (в случае необходимости отправки большего количества пользовательских данных):

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

  };
  return new AuthenticationProperties(data);
}

Если вы не внесли серьезных изменений в проект WebApi, ApplicationOAuthProvider.CreateProperties ссылается только на два места, просто обновите вызывающий код, чтобы передать oAuthIdentity вместе с user.UserName, и вы получите роли пользователя отправленный вместе с ответом маркера доступа:

{
 "access_token": "ZpxAZyYuvCaWgShUz0c_XDLFqpbC0-DIeXl_tuFbr11G-5hzBzSUxFNwNPahsasBD9t6mDDJGHcuEqdvtBT4kDNQXFcjWYvFP7U2Y0EvLS3yejdSvUrh2v1N7Ntz80WKe5G_wy2t11eT0l48dgdyak8lYcl3Nx8D0cgwlQm-pePIanYZatdPFP9q5jzhD-_k9SF-ARTHgf0ePnbvhLBi1MCYQjvfgPKlbBHt0M5qjwGAeFg1IhSVj0gb4g9QTXoiPhRmxGBmjOpGgzxXixavmrpM7cCBFLoR3DCGnIJo6pwT-6VArxlB8-ZyyOZqh_6gGtptd0lIu8iJRUIGwO9HFNkROdoE9T4buwLnhPpWpy9geBjPVwsB1K3xnbch26YbklhxIHVybBxeIVXd17QTw_LjlQ5TJdqpAYfiZ5B9Nx2AFYYYe3--aemh4y1XOIvN",
 "token_type": "bearer",
 "expires_in": 1209599,
 "userName": "MK",
 "roles": "Admin,Public",
 ".issued": "Fri, 23 May 2014 17:36:54 GMT",
 ".expires": "Fri, 06 Jun 2014 17:36:54 GMT"
}

Теперь у вас есть роли, вы можете использовать условные директивы Angular для отображения/скрытия действий в соответствии с ролями пользователя.

Если вам нужно больше разъяснений, сообщите мне.

Edit:

Украшение ваших методов контроллера с помощью атрибута Authorize действительно, так как HttpContext.Current.User.Identity на самом деле является ClaimsIdentity. Но не для жесткой логики безопасности кода внутри приложения, я предпочитаю использовать ClaimsAuthorizationManager

public ActionResult Secure()
{
  if(!ClaimsPrincipalPermission.CheckAccess("resource", "action"))
    return new HttpUnauthorizedResult();

  ViewBag.Message = "You are allowed to perform action on resource.";
  return View();
}

Создание ролей с помощью RoleManager:

RoleManager roleManger = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>());
roleManager.Create(new IdentityRole() { Name = "Admin" });

Назначение ролей с помощью UserManager:

userManager.AddToRole(user.Id, "Admin");

Ответ 2

Есть два способа понять, что вы можете подойти к своей проблеме.

  • включить информацию о роли в токен с помощью хэша или простой строки, поскольку вы создаете токен, а затем можете расшифровать его на angular.

  • Кажется, вы хотите использовать систему идентификации ASP.NET, а также хранить и получать информацию о роли. Если это так, вы можете пройти этот пост, обратите внимание на раздел "Инициализация базы данных для создания роли администратора и администратора".

IMO, # 1 даст вам больше гибкости в отношении того, как вы храните и используете свои пользовательские данные, как # 2, вы следуете за Microsoft IdentityUser, хотя иногда он выглядит волшебным, и он имеет тенденцию ограничивать отправку, и вам нужно потратить время, чтобы понять, как он работает за сценой и заставляет ее работать для вашего проекта.

Чтобы узнать больше о "Индивидуальных учетных записях пользователей", которые вы выбрали во время созданного вами проекта WebAPI, вы можете перейти на http://www.asp.net/visual-studio/overview/2013/creating-web-projects-in-visual-studio#indauth

Ответ 3

У меня очень похожий сценарий, как у вас, но вместо использования токенов для аутентификации я использую Identity Server (Thinktecture), чтобы обработайте мою аутентификацию. Мое приложение перенаправляет на Identity Server аутентификацию, и оно возвращается с некоторыми очень строгими требованиями (имя пользователя и адрес электронной почты). Это происходит, как только кто-то пытается сначала перейти на страницу. Как только пользователь будет аутентифицирован и перенаправлен в мое приложение, я делаю еще один звонок на сервер, чтобы получить разрешения пользователя. Эти разрешения хранятся в службе безопасности (AngularJS), которая также предоставляет метод "hasPermissions". Затем я использую ng-if, чтобы решить, буду ли я отображать определенные части страницы - включая пункты меню. Что-то в этом роде:

var service = {
    currentUser: ...,
    isAuthenticated: function() {
        return ...;
    },
    checkAccess: function(permission) {
        return service.isAuthenticated() ?
            !!(service.currentUser.permissions.indexOf(permission) > -1) : false;
    }
}

Помните, что все права доступа и элементы html видны всем, кто решил нажать кнопку "Инструменты разработчика" и заглянуть в нее. Вы должны выполнить те же проверки на стороне сервера, прежде чем выполнять какие-либо действия. У нас есть настраиваемый атрибут авторизации, основанный на this, который проверяет, есть ли у пользователя необходимые разрешения для выполнения действия MVC/WebAPI до его выполнения для простых случаях или фактически проверить его в действии или ресурсе HTTP, прежде чем делать что-либо, требующее повышенных привилегий.

Если вы хотите, чтобы клиент не видел каких-либо элементов html или определенных разделов вашего сайта, вы можете указать свои шаблоны на действие MVC, которое будет аутентифицироваться, а затем вернуть шаблон HTML или перенаправить на другую страницу (а не область SPA) и попросите их пройти проверку подлинности на сервере до ответа ответа.

Ответ 4

Вот еще один ответ:

В ApplicationOAuthProvider.cs

  public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

            ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);


            if (user == null)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
                return;
            }

просто добавьте настраиваемый заголовок!

 context.OwinContext.Response.Headers.Add("Roles", userManager.GetRoles(user.Id).ToArray());