I am doing an Asp.Net Core Mvc 6 App where I dynamically assign Claims to the user.
I have in the database all Roles that a user must have to access specific fields of the page.
I also have the role of the user.
I am creating Claims where the user's role matches the field page User role. And then I create a ClaimsPrincipal with those list of Roles.
This are the data in the database
This is how I create the permission for the user..
private string[] TransformRowsIntoPermissions(List<RolesAccessModel>? rows, string userRole)
{
List<string> permissionList = new();
if(rows!=null)
{
foreach (RolesAccessModel row in rows)
{
if (row.Roles!=string.Empty && row.Roles != null && !row.Roles.Contains(userRole))
continue;
// if we get here we have a match
if (!permissionList.Contains(row.EventName))
permissionList.Add(row.EventName);
}
}
return permissionList.ToArray();
}
When I have the Permission List, I add it as Claims
private Claim[] CreateClaimsFromArray(string[] permissions)
{
List<Claim> claims = new();
foreach (var permission in permissions)
claims.Add(new Claim(permission, "-"));
return claims.ToArray();
}
And in the main function I save it as ClaimPrincipal
private async void CreateClaimsByUserRole(string role)
{
ClaimsIdentity claimsIdentity =await _iUIConfig.CreateClaimsByUserRole(role);
var userPrincipal = new ClaimsPrincipal(new[] { claimsIdentity });
_ = HttpContext.SignInAsync(userPrincipal);
}
I do not know if line _ = HttpContext.SignInAsync(userPrincipal);
is necessary.
I checked userPrincipal
and it has all the data.
What I need to do is to ask in the View for that claims in order to show or to not Show the fields. But when I ask if it is null...
@{
var claimsIdentity = User.Identity as System.Security.Claims.ClaimsIdentity;
if (claimsIdentity != null)
{
var c = claimsIdentity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
if (c != null)
{
<p>
@c.Type.ToString();
@c.Value.ToString();
</p>
}
else
{
<p>
null
</p>
}
}
}
It is null
If I ask for a specific value
@{
if(System.Security.Claims.ClaimsPrincipal.Current.Claims.ToList().FirstOrDefault(c => c.Type == "DocumentId" && c.Value == "-") != null)
{
.....
}
}
Got an error System.NullReferenceException: 'Object reference not set to an instance of an object.'
Even If a call a Controller/Method and ask for
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
Is null..
I have to do it persistent for all the App.
I am not using Authentication because it is not implemented yet.. I am using SSO from another system. For that reason, for my understanding Cookie are used for Authentication.
In program.cs I only have
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminAccess", policy => policy.RequireRole("Admin"));
options.AddPolicy("ManagerAccess", policy =>
policy.RequireAssertion(context =>
context.User.IsInRole("Admin")
|| context.User.IsInRole("Manager")));
options.AddPolicy("UserAccess", policy =>
policy.RequireAssertion(context =>
context.User.IsInRole("Admin")
|| context.User.IsInRole("Manager")
|| context.User.IsInRole("User")));
});
and
app.UseAuthorization();
What am I missing to do it persistent?
Thanks
ClaimsPrincipal.Current
was used in asp.net,however,in Asp.net core it is no longer set
To retrieve the current user in an ASP.NET Core MVC app,you could try with ControllerBase.User
orHttpContext.User
You could check this document for more details
SignInAsync
creates an encrypted cookie and adds it to the current response.You could get the claims after authenticating successfully in the following request untill the cookie expires(not the current request)
Notice HttpContext.User
could be setted directly
And in View you could get the claims in @ section as below:
@{
var claims = this.ViewContext.HttpContext.User.Claims.ToList();
}