Как хранить пользовательскую информацию в одном месте после входа в систему и доступа к нескольким контроллерам WEB API
Я работаю над веб-API с AngularJS. Я внедрил механизм токенов Web API несколько дней назад и смог войти в приложение, используя токен доступа. Я использовал внешнюю таблицу БД вместо таблицы идентификации ASP.NET для авторизации пользователя.
Я хочу сохранить информацию о пользователе в классе, чтобы к ней можно было легко получить доступ с разных контроллеров после входа пользователя. В настоящее время я использую ClaimsIdentity в классе контроллера для получения информации о пользователе.
UserIdentityViewModel.cs
public class UserIdentityViewModel
{
public string UserName { get; set; }
public Guid UserId { get; set; }
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
var myProvider = new AuthorizationServerProvider();
OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = myProvider
};
app.UseOAuthAuthorizationServer(options);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
AuthorizationServerProvider.cs
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated(); //
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
string userId = context.UserName;
string password = context.Password;
EmployeeAccessBLL chkEmpAccessBLL = new EmployeeAccessBLL();
EmployeeAccessViewModel vmEmployeeAccess = chkEmpAccessBLL.CheckEmployeeAccess(Convert.ToInt32(userId), password);
if(vmEmployeeAccess != null)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("username", vmEmployeeAccess.EmpName));
identity.AddClaim(new Claim("userid", Convert.ToString(vmEmployeeAccess.EmployeeId)));
UserIdentityViewModel vmUser = new UserIdentityViewModel();
vmUser.UserId = vmEmployeeAccess.EmployeeId;
vmUser.UserName = vmEmployeeAccess.EmpName;
context.Validated(identity);
}
else
{
context.SetError("invalid_grant", "Provided username and password is incorrect");
return;
}
}
}
EventController.cs
public class StreamEventController : ApiController
{
[Authorize]
[Route("api/addevent")]
[HttpPost]
public List<string> AddEvent(StreamEventViewModel vmEvent)
{
//Able to get User Information from Identity.Claims
var identity = (ClaimsIdentity)User.Identity;
string userId = identity.Claims
.Where(c => c.Type == "userid")
.Select(c => c.Value).FirstOrDefault();
//Not able to get User Information from following as new object instance gets created
UserIdentityViewModel vmUser = new UserIdentityViewModel();
vmEvent.CreatedBy = vmUser.UserId;
vmEvent.ModifiedBy = vmUser.UserId;
}
}
Вместо того, чтобы писать "Identity.Claims" в каждом методе каждого контроллера, я хочу использовать простой подход get/set или любую другую методологию для получения информации о пользователе. По моему мнению, использование статического класса также плохо, поскольку в нем будет храниться одна информация о пользователе, а информация о входе нескольких пользователей будет пропущена.
Пожалуйста, помогите мне и поделитесь со мной лучшим подходом, который использовался в других проектах Web API для входа в систему.
1 ответ
Вы можете добавить приватную переменную, которая будет установлена в конструкторе контроллера, например так:
// Should only be used in protected methods.
private ClaimsIdentity ThisUser = null;
public MyController()
{
if (User.Identity.IsAuthenticated)
ThisUser = (ClaimsIdentity)User.Identity;
}
[Authorize]
[Route("api/addevent")]
[HttpPost]
public List<string> AddEvent(StreamEventViewModel vmEvent)
{
string userId = ThisUser.FindFirstValue("userid");
}
Или создайте класс User, в который вы загружаете все свойства:
private UserClass ThisUser = null;
public MyController()
{
if (User.Identity.IsAuthenticated)
ThisUser = new UserClass(User);
}
[Authorize]
[Route("api/addevent")]
[HttpPost]
public List<string> AddEvent(StreamEventViewModel vmEvent)
{
string userId = ThisUser.UserId;
}
Где UserClass это что-то вроде:
public class UserClass
{
public string UserId { get; private set; }
public UserClass(IPrincipal user)
{
UserId = user.FindFirstValue("userid");
}
}
Но это просто накладные расходы на одно и то же. Вы можете рассмотреть возможность перенести вещи в расширение. В этом случае вы получите что-то вроде:
public static class RequestExtensions
{
public static UserClass GetUser(this HttpRequestMessage request)
{
return new UserClass(request.GetOwinContext().Authentication.User);
}
public static ClaimsIdentiy GetUser2(this HttpRequestMessage request)
{
return new (ClaimsIdentity)request.GetOwinContext().Authentication.User;
}
}
Который вы можете позвонить:
[Authorize]
[Route("api/addevent")]
[HttpPost]
public List<string> AddEvent(StreamEventViewModel vmEvent)
{
string userId = Request.GetUser.UserId;
string userId2 = Request.GetUser2.FindFirstValue("userid");
}
Я думаю, я бы пошел на Request.GetUser2.FindFirstValue("userid");
Код призван дать вам представление. Я не тестировал код, но думаю, что он должен работать.