I secure my API with identityserver4 and asp.net identity. The identity database has tables roles and roleclaims. For my security model I need roles with her roleclaim. I include role to access token, but I don't understand how to include roleclaim.
//Example of API with roles
new ApiResource("api1", "My API")
{
UserClaims = new []{ "name", "role" }
}
I answered here how to include roles in the access tokens. If you want to additionally include role claims, you will need to use RoleManager.
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
context.IssuedClaims.AddRange(context.Subject.Claims);
var user = await _userManager.GetUserAsync(context.Subject);
var roles = await _userManager.GetRolesAsync(user);
foreach (var role in roles)
{
var roleClaims = await RoleManager.GetClaimsAsync(role);
context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role, role)); //Adds "role" claim
context.IssuedClaims.AddRange(roleClaims); //Adds other role claims
}
}
Related
How can i add role system without identity? I need to member and admin roles.
Login code:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, loginDTO.StrUserID)
};
var userIdentity = new ClaimsIdentity(claims, "login");
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
await HttpContext.SignInAsync(principal);
Startup.cs
services.AddAuthorization(opt =>
{
opt.AddPolicy("Admin", policy => policy.RequireClaim(ClaimTypes.Name));
});
How can i add role system without identity? I need to member and admin roles.
As far as I know, if you used asp.net core cookie authentication , there is no need to build a role system.
We could write the codes in your login logic to check the user role from database.
Then we could add role by adding the ClaimTypes.Role Claim. Then we could use [Authorize(Roles ="Admin")] attribute to let only admin role user access.
More details, you could refer to below codes:
//Here build the logic to get the user role from database, then create a new role claim to add the user role.
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "TestA"),
new Claim(ClaimTypes.Role, "Admin"),
};
var userIdentity = new ClaimsIdentity(claims, "login");
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
HttpContext.SignInAsync(principal);
On the controller:
[Authorize(Roles ="Admin")]
public class AdminController : Controller
How i can change role claim and apply it in terms of one request in Asp.Net Core?
I tried to use
_signInManager.RefreshSignInAsync(user);
But it only works after refreshing the page. Is there any way to update roles for user and change current principal in one request?
You could not change the Current ClaimsPrincipal directly.
To reflect the new claims, you could try _signInManager.CreateUserPrincipalAsync.
To check the new roles in the same request, you may try User.AddIdentity to explict add the new role claim to User.
var roleName = Guid.NewGuid().ToString();
var r1 = User.IsInRole(roleName);
var user = await _userManager.GetUserAsync(User);
var role = await _roleManager.CreateAsync(new IdentityRole { Name = roleName });
await _userManager.AddToRoleAsync(user, roleName);
var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
var claims = claimsPrincipal.Claims.ToList();
User.AddIdentity(new ClaimsIdentity(new List<Claim>() { claims.FirstOrDefault(c => c.Value == roleName) }));
var r3 = User.IsInRole(roleName);
How do I add the new claims in such a way that they persist through requests until the cookie expires?
I am using OWIN middle ware, on-premises authentication to authenticate the users logging into the system.
The sign-in part is successful, and I added Roles to the user claims provided by the ws-federation to help authorize the user for certain action methods.
At the time of login, in the controller, I have written the following to add the roles:
string[] roles = { "Role1", "Role2" };
var identity = new ClaimsIdentity(User.Identity);
foreach (var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.Role, role));
}
var authenticationManager = HttpContext.GetOwinContext().Authentication;
authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant
(new ClaimsPrincipal(identity),
new AuthenticationProperties { IsPersistent = true });
But when I check the claims at the next request, I don't see the role claims.
After successful authentication I believe you added custom claims (normally to some event handler once successfully authenticated). Now in order to persist that information in subsequent request you need to use CookieAuthentication middle ware before your authentication owin in pipeline.
How it works :
Upon successful authentication first time and addition of custom claims, claims will be transformed into sort of auth cookie and sent back to client. Subsequent request will carry this auth cookie. CookieAuthentication middle ware on finding auth cookie will set your Thread.CurrentPriciple with claims obtained from cookie.
During first time request when cookie middle ware does see any auth cookie, it passes request to next middle ware in pipe line (Authentication owin in your case) to challenge user for login.
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = "Cookies",
AuthenticationMode= AuthenticationMode.Active,
CookieName="XXXXX",
CookieDomain= _cookiedomain,
/* you can go with default cookie encryption also */
TicketDataFormat = new TicketDataFormat(_x509DataProtector),
SlidingExpiration = true,
CookieSecure = CookieSecureOption.Always,
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = _clientID,
Authority = _authority,
RedirectUri = _redirectUri,
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = SecurityTokenValidated,
AuthenticationFailed = (context) =>
{
/* your logic to handle failure*/
}
},
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
ValidIssuers = _validIssuers,
ValidateIssuer = _isValidIssuers,
}
});
EDIT: (Additional information)
Pretty much the exact code as above works for ws federation also, with the same logic and everything.
SecurityTokenValidated = notification =>
{
ClaimsIdentity identity = notification.AuthenticationTicket.Identity;
string[] roles = { "Role1", "Role2" };
foreach (var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.Role, role));
}
return Task.FromResult(0);
}
You need to use the same AuthenticationType that you used in Startup.ConfigureAuth. For example:
In Startup.ConfigureAuth:
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
//....
});
And in your login code (provided in the question):
var identity = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie);
Or make sure that the User.Identity has the same AuthenticationType, and you're good to use that like you did:
var identity = new ClaimsIdentity(User.Identity);
Now the important part is that for the login, you should add the claims before singing the use in, not after. Something like this:
HttpContext.GetOwinContext().Authentication.SignIn(identity);
You can add the claims after signing in, but you will be modifying the cookie right after it is created, which is not efficient. If in some other code you need to modify the claims, then you can use something similar to your code, but you must get the context from Current:
HttpContext.Current.GetOwinContext().Authentication.AuthenticationResponseGrant =
new AuthenticationResponseGrant(new ClaimsPrincipal(identity),
new AuthenticationProperties { IsPersistent = true });
So you can fix your code by simply adding Current like above, but that's not efficient for the login code and it is better to pass the claims to the SignIn function.
you can do the following in WEB API C # (SOAP),(STORED PROCEDURES)
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
LoginModel model = new LoginModel();
//validate user credentials and obtain user roles (return List Roles)
//validar las credenciales de usuario y obtener roles de usuario
var user = model.User = _serviceUsuario.ObtenerUsuario(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "El nombre de usuario o la contraseƱa no son correctos.cod 01");
return;
}
var stringRoles = user.Roles.Replace(" ", "");//It depends on how you bring them from your DB
string[] roles = stringRoles.Split(',');//It depends on how you bring them from your DB
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
foreach(var Rol in roles)
{
identity.AddClaim(new Claim(ClaimTypes.Role, Rol));
}
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Email, user.Correo));
identity.AddClaim(new Claim(ClaimTypes.MobilePhone, user.Celular));
identity.AddClaim(new Claim("FullName", user.FullName));//new ClaimTypes
identity.AddClaim(new Claim("Empresa", user.Empresa));//new ClaimTypes
identity.AddClaim(new Claim("ConnectionStringsName", user.ConnectionStringsName));//new ClaimTypes
//add user information for the client
var properties = new AuthenticationProperties(new Dictionary<string, string>
{
{ "userName",user.NombreUsuario },
{ "FullName",user.FullName },
{ "EmpresaName",user.Empresa }
});
//end
var ticket = new AuthenticationTicket(identity, properties);
context.Validated(ticket);
}
In past MVC versions I was able to do
<roleManager enabled="true" defaultProvider="...." ...
in to the web.config to get a custom role provider, but that doesn't seem to be the case anymore.
Essentially what I want to do is:
The user logs in.
On success, get roles for user from external source.
Apply roles to user to be used in code.
Match user roles to roles in custom RoleProvider
How do I do this in ASP.NET Core?
If you're using simple cookie-based authentication instead of the Identity framework, you can add your roles as claims and they will be picked up by User.IsInRole(...), [Authorize(Roles = "...")], etc.
private async Task SignIn(string username)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username)
};
// TODO: get roles from external source
claims.Add(new Claim(ClaimTypes.Role, "Admin"));
claims.Add(new Claim(ClaimTypes.Role, "Moderator"));
var identity = new ClaimsIdentity(
claims,
CookieAuthenticationDefaults.AuthenticationScheme,
ClaimTypes.Name,
ClaimTypes.Role
);
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(identity),
new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddMonths(1)
}
);
}
I'm using ASP.NET MVC 5 project with identity 2.1.0 and VS2013 U4. I want to add claims to user during registration in order to be stored in db. These claims represent user custom properties.
As I created a web page for administrator to create/edit/delete users, I'm still using create method from AccountController to create a user, but I don't want to login that user. How can I add those claims to the user ?
You probably already have a UserManager class. You can use that one to create users and to add claims.
As an example in a controller:
// gather some context stuff
var context = this.Request.GetContext();
// gather the user manager
var usermanager = context.Get<ApplicationUserManager>();
// add a country claim (given you have the userId)
usermanager.AddClaim("userid", new Claim(ClaimTypes.Country, "Germany"));
In order for this to work you need to implement your own UserManager and link it with the OWIN context (in the example it's ApplicationUserManager which basically is class ApplicationUserManager : UserManager<ApplicationUser> { } with only a small amount of configuration added). A bit of reading is available here: https://msdn.microsoft.com/en-us/library/dn613290%28v=vs.108%29.aspx
you can use Like
private void SignInAsync(User User)
{
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, User.Employee.Name));
claims.Add(new Claim(ClaimTypes.Email, User.Employee.EmailId));
claims.Add(new Claim(ClaimTypes.Role, User.RoleId.ToString()));
var id = new ClaimsIdentity(claims,
DefaultAuthenticationTypes.ApplicationCookie);
var claimsPrincipal = new ClaimsPrincipal(id);
// Set current principal
Thread.CurrentPrincipal = claimsPrincipal;
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(id);
}
after login pass the User table value in this function
SignInAsync(result);
you can get clam value like
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
// Get the claims values
string UserRoleValue = identity.Claims.Where(c => c.Type == ClaimTypes.Role)
.Select(c => c.Value).SingleOrDefault();
You can, in fact, create claims at the same time you create the user account.
Just add the claims to the user object before you call CreateAsync on the user manager.
var identityUser = new IdentityUser
{
UserName = username,
Email = email,
// etc...
Claims = { new IdentityUserClaim { ClaimType = "SomeClaimType", ClaimValue = "SomeClaimValue"} }
};
var identityResult = await _userManager.CreateAsync(identityUser, password);
This will create the user and associate the claims with the user as one logical operation with persistence.