How to extend IdentityUser as a claim in ASP.NET Core / MVC 6 / EF7? - asp.net-core

I am building a site that has Users that belong to an Account. The account is identified by an AccountId which is a foreign key for most data in the DB such as Charges (associated to an Account) or Receipts (associated to an Account).
Rather than hitting the DB every time the repository needs to be polled for data to get the user's AccountId, I wanted to add the AccountId as a claim. The goal being to do something like:
_repository.GetAllChargesByAccountId(User.Identity.GetAccountId());
I'm finding only tidbits and partial solutions for this and I haven't been able to resolve some differences between those examples and my specific environment (ASP.NET Core RC1, MVC 6, EF7).
I have derived a class from IdentityUser for adding attributes about the user:
public class UserIdentity : IdentityUser {
public static object Identity { get; internal set; }
public int AccountId { get; set; }
}
I have created a UserIdentityContext that derives from IdentityDbContext that I'm using for my EF user store.
And I have the following AuthController:
public class AuthController : Controller {
private SignInManager<UserIdentity> _signInManager;
public AuthController(SignInManager<UserIdentity> signInManager) {
_signInManager = signInManager;
}
public IActionResult Login() {
if (User.Identity.IsAuthenticated)
return RedirectToAction("Dashboard", "App");
return View();
}
[HttpPost]
public async Task<ActionResult> Login(LoginViewModel vm, string returnUrl) {
if (ModelState.IsValid) {
var signInResult = await _signInManager.PasswordSignInAsync(vm.Username, vm.Password, true, false);
if (signInResult.Succeeded) {
if (String.IsNullOrWhiteSpace(returnUrl))
return RedirectToAction("Dashboard", "App");
else return RedirectToAction(returnUrl);
} else {
ModelState.AddModelError("", "Username or password is incorrect.");
}
}
return View();
}
public async Task<IActionResult> Logout() {
if (User.Identity.IsAuthenticated) {
await _signInManager.SignOutAsync();
}
return RedirectToAction("Index", "App");
}
}
Looking at other posts, it sounds like I need to add an IdentityExtension in order to access the claim as User.Identity.GetAccountId() and generate a custom user identity as in this answer: How to extend available properties of User.Identity but obviously this is done in an older version and many of the method calls are not applicable anymore.
Thanks in advance for any answers or guidance.

if you have added a claim for AccountId you can then easily write an extension method to get it:
public static string GetAccountId(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
var claim = principal.FindFirst("AccountId");
return claim != null ? claim.Value : null;
}
if you need help on how to add a custom claim see this question

Related

ASP.NET CORE Add easily accessible properties to logged user

In our Asp.Net Core (2.2) MVC project we had to use an existing database (including all user & role related tables) from our previous Asp.Net Web app project.
Retrieving user data in asp.net web app (and having it available throughout the website) was preatty simple: upon login fill a custom user class/object with all the properties you need, save it as a Session variable and you call it wherever you need it (without going to the database).
This seems to me a lot harder to achieve in Asp.Net Core. What I have so far is:
ApplicationUser class:
public class ApplicationUser : IIdentity
{
public int Id { get; set; }
public Uporabnik Uporabnik { get; set; }
public string AuthenticationType { get; set; }
public bool IsAuthenticated { get; set; }
public string Name { get; set; }
}
Login form:
public IActionResult Prijava(PrijavaModel model)
{
// check user credentials
//
// ... validation code here ...
//
if (uporabnik != null)
{
//Create the identity for the user
var identity = new ClaimsIdentity(new[] {
new Claim("Email", model.Email),
new Claim("Id", uporabnik.IdWebUser.ToString()),
new Claim("Name", uporabnik.ImeInPriimek),
new Claim(ClaimTypes.Name, uporabnik.ImeInPriimek),
new Claim(ClaimTypes.PrimarySid, uporabnik.IdWebUser.ToString())
}, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
var login = HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
return RedirectToAction("Index", "Home");
}
return View();
}
Now to retrieve the data in a controller I have to do something like this:
// id
int idUser = int.Parse(#User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
// or email
string email = #User.Claims.FirstOrDefault(x => x.Type == "Email").Value;
Well, this all works fine, but it's definitely not practical. To access any other user data I can go to the database (by "ID") and retrieve it, but I don't think this is the right way to do it!?!
Can I expand the identity class in such a way that I can set the extra properties I need at login time and retrive in a fashion similar to something like this:
var property1 = #User.Property1;
var property2 = #User.Property2;
// or
var property1 = #User.MyExtraProperties.Property1;
var property2 = #User.MyExtraProperties.Property2;
Is it possible (and also keeping it simple)?
EDIT: since there are no answers/suggestions, can I do the same thing with a different approach?
Look like you only want to call your properties in a better way?
public class ApplicationUser : IdentityUser
{
public string CustomName { get; set; }
}
Assuming you have done adding your extra properties, you could create an extension method for your properties, so you can later call them like User.Identity.GetCustomName().
namespace Project.Extensions
{
public static class IdentityExtensions
{
public static string GetCustomName(this IIdentity identity)
{
var claim = ((ClaimsIdentity)identity).FindFirst("CustomName");
return (claim != null) ? claim.Value : string.Empty;
}
}
}
Note that I didn't include the part where you add the claims, because you already have it. In this case, you should have CustomName claim.
Also, #Dementic is right about the session. If a user is removed/disabled, he would still have access to. So, having a db call each time you need to fetch information is correct.

ASp.net core 2 Identity app sometimes looses claim when kept logged in

I have an authorization handler, which is meant to restrict users to accessing info only for the organization they belong to, or ANY if they are of a certain account type (known as SuperAdmin here). Aforementioned account type may or may not have an associated Organization, which happens to be a navigation property. It should be mentioned I am working with "user" classes extended from ApplicationUser in the Identity framework.
Here's the handler:
public class OrganizationHandler : AuthorizationHandler<SameOrgRequirment,
Organization>
{
protected override Task
HandleRequirementAsync(AuthorizationHandlerContext context,
SameOrgRequirment requirement, Organization resource)
{
var value = context.User.FindFirst( "OrganizationID").Value;
long claimValue = long.Parse(value);
if(claimValue==resource.Id)
{
context.Succeed(requirement);
}
else
{
string orgClaimValue = context.User.FindFirst(c => c.Type ==
"AccountTypes").Value;
AccountTypes claimAsType =
(AccountTypes)Enum.Parse(typeof(AccountTypes), orgClaimValue);
if(claimAsType == AccountTypes.SuperAdmin)
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
}
public class SameOrgRequirment:IAuthorizationRequirement{}
The problem is I am SOMETIMES getting a NullReferenceException on the line
var value = context.User.FindFirst( "OrganizationID").Value;
which makes no sense as all users in my dev setup have an organizationId navigation property. Inspecting the ClaimsPrincipal I see the AccountTypes claim (see below) exists but the other, OrganizationId does not when this NullReferenceException is thrown.
I have overridden the AppClaimsPrincipalFactory to create these claims:
public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>
{
public AppClaimsPrincipalFactory(
UserManager<ApplicationUser> userManager
, RoleManager<ApplicationRole> roleManager
, IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{ }
public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
if (!string.IsNullOrWhiteSpace(user.Type.ToString()))
{
((ClaimsIdentity)principal.Identity).AddClaims(new[]
{
new Claim("AccountTypes", user.Type.ToString())
});
}
try
{
if (!string.IsNullOrWhiteSpace(user.Organization.Id.ToString()))
{
//Used later to restrict data
((ClaimsIdentity)principal.Identity).AddClaims(new[]
{
new Claim("OrganizationId", user.Organization.Id.ToString()),
});
}
}
catch(NullReferenceException ex)
{
((ClaimsIdentity)principal.Identity).AddClaims(new[]
{
new Claim("OrganizationId", "-1"),
});
}
return principal;
}
}
The AccountTypes claim doesnt seem to get lost.
The only thing I have narrowed down is that this only seems to happen for an account where Remember Me? is checked and the app is closed and reopened via visual studio. If I log out and log back with the same account, it works fine! All claims are there and the handler works correctly. Being able to stay logged is a customer requirement so I can't really change that.

Generic authorization with handler

I'm trying to implement authorization in my ASP.NET Core 2.0 Web app.
This app has like 20 models, each with a controller implementing at least a CRUD. I found these two pages and I liked the idea of using a handler to authorize requisitions. I would like initially to implement authorization by user, i.e., a user has only permission to see/edit his own entities. All my database entities have an OwnerId field.
These examples I found seem to only work for one specific controller.
So, my question is: is it possible to create one authorization handler for all controllers?
Have you found a solution or workaround yet that works with the authorization handler or authorization attributes? I have the exact same setup as you do.
I was trying to create a generic attribute to serve all may Entity CRUD owner checks, but generic attributes are not allowed by design.
The only two (unsatisfying) solutions that I came up with are:
Within the controller action, get the ownerId from the User, forward it all the way to your CRUD and include there a check for the ownerId. However, the code must be duplicated for every action in every controller.
[HttpGet("{id}"]
public async Task<IActionResult> GetById(int id)
{
var stringGuid = User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
if (String.IsNullOrWhiteSpace(stringGuid)) return Unauthorized();
var ownerGuid = new Guid(stringGuid);
var entity = _yourCrudInstance.GetById(id, ownerGuid);
return Ok(entity);
}
Add a method to your CRUD repository like bool IsOwner(Guid ownerId) and use this method when creating the custom authorization handler (by creating a custom requirement together with a custom handler). This eliminates code duplication in the controller, because you can create a new policy with this custom authorization handler and consequently you can simply decorate every action with a [Authorize(Policy = "yourOwnershipPolicy")]. But still, there must be a service created for each and every controller. Moreover, the IsOwner(...) method adds an additional database call compared to solution 1 - one db call for checking the ownership (during authorization check) and one db call for actually getting the entity (by working through the controller action).
[Authorize(Policy = "yourOwnershipPolicy")]
public async Task<IActionResult> GetById(int id)
{
var entity = _yourCrudInstance.GetById(id);
return Ok(entity);
}
I am going with the first solution until I found a way to create a generic authorization handling for my generic CRUD repository, because one may forget creating the required authorization policy for a new entity, but one cannot forget to supply the parameter ownerId to .GetById(id, ownerGuid), provided there is no overload method, or the code doesn't compile.
Update:
I found a third solution in which was able to create a kind of generic authorization attribute. The trick was to use the type of concrete repository as input parameter in the authorization attribute. Yet, there is still a limitation: The authorization attribute must be copied for every type of Id, for example int Id, Guid id, etc. But still, this reduces repeated code to the types of ids. In most cases, people only have one type of id, probably int or Guid.
Here some code that demonstrates my architecture. It is heavily summarized and redacted, but should compile successfully. My original code is working and in production:
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
[Route("api/yourcontroller")]
public class YourApiController : Controller
{
private readonly YourEntityXYZRepository _repo;
public YourApiController(YourDbContext yourDbContext)
{
_repo = new YourEntityXYZRepository(yourDbContext);
}
[HttpGet("{id}")]
[AuthorizeOwnerIntId(typeof(YourEntityXYZRepository), Policy = "YourCustomPolicy")]
public async Task<IActionResult> GetById(int id)
{
var entity = _repo.GetById(id);
return Ok(entity);
}
}
// The "generic" authorization attribute for type int id
// Similar authorization attributes for every type of id must be created additionally, for example Guid
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AuthorizeOwnerIntIdAttribute : AuthorizeAttribute, IAuthorizationFilter
{
private object _entityRepositoryObject;
private IAsyncOwnerIntId _entityRepository;
private readonly Type _TCrudRepository;
public AuthorizeOwnerIntIdAttribute(Type TCrudRepository)
{
_TCrudRepository = TCrudRepository;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var yourDbContext = context.HttpContext.RequestServices.GetService<YourDbContext>();
_entityRepositoryObject = Activator.CreateInstance(_TCrudRepository, yourDbContext);
_entityRepository = _entityRepositoryObject as IAsyncOwnerIntId;
var user = context.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
// it isn't needed to set unauthorized result
// as the base class already requires the user to be authenticated
// this also makes redirect to a login page work properly
// context.Result = new UnauthorizedResult();
return;
}
// get entityId from uri
var idString = context.RouteData.Values["id"].ToString();
if (!int.TryParse(idString, out var entityId))
{
context.Result = new UnauthorizedResult();
return;
}
// get subjectId from user claims
var ownerIdString = context.HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
if (!Guid.TryParse(ownerIdString, out var ownerGuid))
{
context.Result = new UnauthorizedResult();
return;
}
if (!_entityRepository.IsEntityOwner(entityId, ownerGuid))
{
context.Result = new UnauthorizedResult();
}
}
}
// Your concrete repository
public class YourEntityXYZRepository : AsyncCrud<YourEntityXYZ, int>,
IAsyncOwnerIntId // Note that type concrete IAsyncOwnerIntId is only implemented in concrete repository
{
public YourEntityXYZRepository(YourDbContext yourDbContext) : base(yourDbContext)
{
}
}
// Your generic Crud repository
public abstract class AsyncCrud<TEntity, TId> : IAsyncCrud<TEntity, TId>
where TEntity : class, IEntityUniqueIdentifier<TId>, IEntityOwner
where TId : struct
{
protected YourDbContext YourDbContext;
public AsyncCrud(YourDbContext yourDbContext)
{
YourDbContext = yourDbContext;
}
// Note that the following single concrete implementation satisfies both interface members
// bool IsEntityOwner(TId id, Guid ownerGuid); from IAsyncCrud<TEntity, TId> and
// bool IsEntityOwner(int id, Guid ownerGuid); from IAsyncOwnerIntId
public bool IsEntityOwner(TId id, Guid ownerGuid)
{
var entity = YourDbContext.Set<TEntity>().Find(id);
if (entity != null && entity.OwnerGuid == ownerGuid)
{
return true;
}
return false;
}
// Further implementations (redacted)
public Task<bool> SaveContext() { throw new NotImplementedException(); }
public Task<TEntity> Update(TEntity entity){ throw new NotImplementedException(); }
public Task<TEntity> Create(TEntity entity, Guid ownerGuid) { throw new NotImplementedException(); }
public Task<bool> Delete(TId id) { throw new NotImplementedException(); }
public Task<bool> DoesEntityExist(TId id) { throw new NotImplementedException(); }
public virtual Task<TEntity> GetById(TId id) { throw new NotImplementedException(); }
}
// The interface for the Crud operations
public interface IAsyncCrud<TEntity, TId>
where TEntity : class, IEntityUniqueIdentifier<TId>
where TId : struct
{
bool IsEntityOwner(TId id, Guid ownerGuid);
Task<bool> DoesEntityExist(TId id);
Task<TEntity> GetById(TId id);
Task<TEntity> Create(TEntity entity, Guid ownerGuid);
Task<TEntity> Update(TEntity entity);
Task<bool> Delete(TId id);
Task<bool> SaveContext();
}
// The interface for the concrete type method for int id
// Similar interfaces for every type of id must be created additionally, for example Guid
public interface IAsyncOwnerIntId
{
bool IsEntityOwner(int id, Guid ownerGuid);
}
// Typical db context
public class YourDbContext : DbContext
{
public YourDbContext(DbContextOptions<YourDbContext> options) : base(options)
{
}
public DbSet<YourEntityXYZ> YourEntityXYZ { get; set; }
}
public class YourEntityXYZ : IEntityUniqueIdentifier<int>, IEntityOwner
{
public int Id { get; set; }
public Guid? OwnerGuid { get; set; }
// ... Additonal custom properties
}
public interface IEntityUniqueIdentifier<TId>
where TId : struct
{
TId Id { get; set; }
}
public interface IEntityOwner
{
Guid? OwnerGuid { get; set; }
}

AutoMapper Update Actions in ASP.NET MVC

This is probably quite straight forward for some, however I'm a bit confused and can't find a decent example. Say I'm using view models and my POST action takes in that view model. Typically I would do something along the following lines:
[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
User user = Mapper.Map<UserViewModel, User>(uvm);
_repository.Update(user);
return RedirectToAction("Index");
}
Although this isn't the full picture. The mapping would work fine, however if I were to just update what I've mapped then it'd get rid of valuable data in the database because of course in this case I'm not updating the password or other details.
My repository looks something like this:
public void Update(User user)
{
User u = Session.QueryOver<User>().Where(x => x.UserName == user.UserName).SingleOrDefault();
if (u == null)
throw new Exception("User not found");
u.Forename = user.Forename;
u.Surname = user.Surname;
u.EmailAddress = user.EmailAddress;
}
[I'm using NHibernate so it'll save the object back to the DB once the session is closed (after the request has finished) automatically for me.]
So my question is, in my repository should I load the "User" entity, then update the values I want, and then save it back, or is there another method to do this? The reason I ask is because it seems a bit... "manual" if you see what I mean? Perhaps it is correct, but I just wanted to see opinions of those with more experience in this area.
Cheers
I use the following approach:
[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
User user = _userRepository.FindById(uvm.Id);
user.Forename = uvm.Forename;
user.Surname = uvm.Surname;
user.EmailAddress = uvm.EmailAddress;
_userRepository.Update(user);
return RedirectToAction("Index");
}
UPDATE:
To address the comments about AutoMapper here's how to proceed:
Let's take for example the following classes:
public class UserViewModel
{
public string Forename { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
}
public class User
{
public string Forename { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
}
We don't want to modify the user password in the UI. So we express our intention to AutoMapper:
Mapper
.CreateMap<UserViewModel, User>()
.ForMember(dest => dest.Password, opt => opt.Ignore());
and then:
[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
// Fetch the original model we would like to update
User user = _userRepository.FindById(uvm.Id);
Mapper.Map(uvm, user);
// At this stage the user model will have its
// Forename, Surname and EmailAddress properties
// updated from the view model and its Password property
// will remain the one we got from the repository
_userRepository.Update(user);
return RedirectToAction("Index");
}
UPDATE 2:
To address the question in the comments about configuring AutoMapper I usually use Profiles:
public class UsersProfile : Profile
{
protected override void Configure()
{
Mapper
.CreateMap<UserViewModel, User>()
.ForMember(dest => dest.Password, opt => opt.Ignore());
Mapper
.CreateMap<User, UserViewModel>();
}
}
and then have a registry class which registers all the mappers:
public class MappingsRegistry
{
public static void Configure()
{
Mapper.AddProfile(new UsersProfile());
Mapper.AddProfile(new SomeOtherProfile());
...
}
}
which is called in Application_Start:
MappingsRegistry.Configure();
Finally my controllers have a reference to the mapping engine:
public class UsersController : Controller
{
private readonly IUsersRepository _repository;
private readonly IMappingEngine _mappingEngine;
public ContratsFCController(IUsersRepository repository, IMappingEngine mapperEngine)
{
_repository = repository;
_mapperEngine = mapperEngine;
}
[AutoMap(typeof(User), typeof(UserViewModel))]
public ActionResult Update(int id)
{
var user = _repository.FindById(id);
return View(user);
}
[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
if (!ModelState.IsValid)
{
return View(uvm);
}
var user = _repository.FindById(uvm.Id);
_mapperEngine.Map(uvm, user);
_repository.Update(user);
return RedirectToAction("Index");
}
}
Now all that's left is to instruct your DI framework to pass the Mapper.Engine property to the constructor and in your unit tests obviously substitute them with an appropriate mock.

ASP.NET MVC 3 using Authentication

How can I save something using FormsAuthentication? I don't want to store UserId through URL's.
For example, now I have this code:
//UserController class:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (repository.ValidateUser(model.Login, model.Password))
{
FormsAuthentication.SetAuthCookie(model.Login, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Project", "Index");
}
}
else
{
ModelState.AddModelError("", "Incorrect name or password.");
}
}
return View(model);
}
ProjectController class:
public ViewResult Index()
{
return View(repository.GetUserProjects(
this.ControllerContext.HttpContext.User.Identity.Name));
}
ProjectRepository:
ProjectsContext context = new ProjectsContext();
UsersContext uCnt = new UsersContext();
public IEnumerable<Project> GetUserProjects(String username)
{
if (String.IsNullOrEmpty(username))
throw new ArgumentNullException("username", "Login is empty");
return this.uCnt.Users
.FirstOrDefault(u => u.Login == username)
.Projects
.ToList();
}
ProjectController and ProjectRepository don't looks like good code... Maybe someone can give advise, how to store UserID without using URL's? Best way to do this is save IDs on autorisation, I think. I don't found any properties in User.Identity to do this...
UPD
I beg a pardon, but I forgot to say that I'm using MVC-3 with Razor view.
And that UserId is not a string (User.Identity.Name is a string) it could be GUID or maybe my own object...
Save the UserID in the UserData property of the FormsAuthentication ticket in the authorization cookie when the user logs on:
string userData = userID.ToString();
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.Email,
DateTime.Now, DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),
createPersistentCookie, userData);
string hashedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashedTicket);
HttpContext.Current.Response.Cookies.Add(cookie);
You can read it back in the PostAuthenticateRequest method in Global.asax:
HttpCookie formsCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (formsCookie != null)
{
FormsAuthenticationTicket auth = FormsAuthentication.Decrypt(formsCookie.Value);
Guid userID = new Guid(auth.UserData);
var principal = new CustomPrincipal(Roles.Provider.Name, new GenericIdentity(auth.Name), userID);
Context.User = Thread.CurrentPrincipal = principal;
}
Note that in this case, CustomPrincipal derives from RolePrincipal (although if you're not using Roles, I think you need to derive from GenericPrincipal), and simply adds the UserID property and overloads the constructor.
Now, wherever you need the UserID in your app, you can do this:
if(HttpContext.Current.Request.IsAuthenticated)
Guid userID = ((CustomPrincipal)HttpContext.Current.User).UserID;
Why not first make all your authorization calls via an interface. This way all of your code which uses authentication does not need to be concerned about how the login is performed, or how the Indentity is stored, etc.
public interface IAuthorization
{
bool ValidateUser(LoginUser u, string password);
LoginUser GetCurrentUser();
void LogIn(LoginUser user);
void LogOut();
IIdentity GetCurrentUserIdentity();
}
Implemenation for the IIdentity GetCurrentUserIdentity could be any way you like, but is commonly seen as a call to "HttpContext.Current.User.Identity"
public class Authorization : IAuthorization
{
/// <summary>
/// Get the IIdentity for the current logged in user
/// </summary>
/// <returns>IIdentity</returns>
public virtual IIdentity GetCurrentUserIdentity()
{
return HttpContext.Current.User.Identity;
}
/// <summary>
/// Log the user in
/// </summary>
/// <param name="user">User details</param>
public void LogIn(LoginUser user)
{
InvalidCredentialsOnNullUser(user);
FormsAuthentication.SetAuthCookie(user.Name, false);
}
/// <summary>
/// Log the user out
/// </summary>
public void LogOut()
{
FormsAuthentication.SignOut();
}
private static void InvalidCredentialsOnNullUser(LoginUser user)
{
if (user == null)
{
throw new InvalidCredentialException("That user doesn't exist or is not valid.");
}
}
// other methods....
}
The LoginUser class you see is information which is retrieved about a membership user. This is commonly done via a MembershipProvider but of course can be done other ways.
public class LoginUser
{
public string Name;
public Guid Key;
public string EmailAddress;
public bool IsApproved;
public bool IsLockedOut;
public DateTime CreationDate;
public DateTime? LastLoginDate;
public DateTime? LastPasswordChangedDate;
}
I'm not sure I understand the question correctly but if you're referring to a way of retrieving who the current user is without passing it through the URL (e.g. http://localhost/controller/action?username=RAMe0) then you can look at using Thread.CurrentPrincipal.Identity.Name or HttpContext.Current.User
There are subtle differences between the two however. Look here for more details.
Using FormsAuthentication you can store the Username in the User.Identity.Name property. Here's a simple example of what you probably are looking for. (Using the same SetAuth you're already using)
public ViewResult Index() {
return View(repository.GetUserProjects(this.User.Identity.Name));
}
This doesn't require you to pass the username in through a QueryString parameter.