.NET Learning Notes: How to use Identity
Reference: https://learn.microsoft.com/en-us/aspnet/core/security/?view=aspnetcore-9.0 https://blog.csdn.net/ousetuhou/article/details/135392012 Authentication Authorization Data protection HTTPS enforcement Safe storage of app secrets in development XSRF/CSRF prevention Cross Origin Resource Sharing(CORS) Cross-Site Scripting(XSS) attacks Authentication is a process in which a user provides credentials that are then compared to those stored in an operating system, database, app or resource. If they match, users authenticate successfully, and can then perform actions that they're authorized for, during an authorization process. The authorization refers to the process that determines what a user is allowed to do. An authentication scheme's authenticate action is responsible for constructing the user's identity based on request context. An authentication challenge is invoked by Authorization when an unauthenticated user requests an endpoint that requires authentication. A challenge action should let the user know what authentication mechanism to use to access the requested resource. An authentication scheme's forbid action is called by Authorization when an authenticated user attempts to access a resource they're not permitted to access. How to use Identity? 1.Create MyUser class to inherit IdentityUser, T is type of primary key. 2.Create MyRole class to inherit IdentityRole, Tis type of Primary key. 3.Create MyDbContext class to inherit IdentityDbContext, and override the constructor which has a options parameter. IdentityDbContext also should define all user, role, and key type. public class ApplicationDbContext : IdentityDbContext { public ApplicationDbContext(DbContextOptions options) : base(options) { } } 4.Add configuration to DI framework. builder.Services.AddDbContext(options => { var connectionString = builder.Configuration.GetValue("MySQLConnectionString", string.Empty); options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); }); builder.Services.AddDataProtection(); builder.Services.AddIdentityCore( options => { // for test, reduce the strength of password options.Password.RequireDigit = false; options.Password.RequireLowercase = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequiredLength = 6; options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider; options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider; }); var identityBuilder = new IdentityBuilder(typeof(MyUser), typeof(MyRole), builder.Services); identityBuilder.AddEntityFrameworkStores() .AddDefaultTokenProviders().AddRoleManager() .AddUserManager(); 5.Add a DbContextFactory implement IDesignTimeDbContextFactory, because EF Core may not be able to migrate. public class DbContextDesignTimeFactory: IDesignTimeDbContextFactory { public ApplicationDbContext CreateDbContext(string[] args) { DbContextOptionsBuilder builder = new DbContextOptionsBuilder(); var connectionString = arg[0]; builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); return new ApplicationDbContext(builder.Options); } } 6.Database migrate How to use JWT? 1.Configurate JWT "JwtTokenOption": { "Issuer": "ChenLi", "Audience": "EveryOne", "IssuerSigningKey": "ChenLi$%%^&%*!&^@*GUH976&^^&T*u34", "AccessTokenExpiresMinutes": "30" } 2.Create a option public class JwtTokenOption { public const string JwtKey = "JwtTokenOption"; public string Issuer { get; set; } public string Audience { get; set; } public string IssuerSigningKey { get; set; } public int AccessTokenExpiresMinutes { get; set; } } 3.Add JwtTokenOption Configuration builder.Services.Configure(builder.Configuration.GetSection(JwtTokenOption.JwtKey)); 4.Install JWTBearer NuGet package Microsoft.AspNetCore.Authentication.JwtBearer 5.Add JwtBearer to Authentication builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { var jwtTokenOption = builder.Configuration.GetSection(JwtTokenOption.JwtKey).Get(); options.RequireHttpsMetadata = false; options.SaveToken = true; options.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = true, ValidIssuer = jwtTokenOption.Issuer, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtTokenOption.IssuerSigningKey)), ValidateAudience = true, ValidAudience = jwtTokenOption.Audience, ValidateLifetime = true, ClockSkew = TimeSpan.FromMin

Reference:
https://learn.microsoft.com/en-us/aspnet/core/security/?view=aspnetcore-9.0
https://blog.csdn.net/ousetuhou/article/details/135392012
- Authentication
- Authorization
- Data protection
- HTTPS enforcement
- Safe storage of app secrets in development
- XSRF/CSRF prevention
- Cross Origin Resource Sharing(CORS)
- Cross-Site Scripting(XSS) attacks
Authentication is a process in which a user provides credentials that are then compared to those stored in an operating system, database, app or resource. If they match, users authenticate successfully, and can then perform actions that they're authorized for, during an authorization process. The authorization refers to the process that determines what a user is allowed to do.
An authentication scheme's authenticate action is responsible for constructing the user's identity based on request context.
An authentication challenge is invoked by Authorization when an unauthenticated user requests an endpoint that requires authentication. A challenge action should let the user know what authentication mechanism to use to access the requested resource.
An authentication scheme's forbid action is called by Authorization when an authenticated user attempts to access a resource they're not permitted to access.
How to use Identity?
1.Create MyUser class to inherit IdentityUser, T is type of primary key.
2.Create MyRole class to inherit IdentityRole, Tis type of Primary key.
3.Create MyDbContext class to inherit IdentityDbContext, and override the constructor which has a options parameter.
IdentityDbContext also should define all user, role, and key type.
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}
}
4.Add configuration to DI framework.
builder.Services.AddDbContext(options
=>
{
var connectionString = builder.Configuration.GetValue("MySQLConnectionString", string.Empty);
options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
});
builder.Services.AddDataProtection();
builder.Services.AddIdentityCore(
options =>
{
// for test, reduce the strength of password
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 6;
options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
});
var identityBuilder = new IdentityBuilder(typeof(MyUser), typeof(MyRole), builder.Services);
identityBuilder.AddEntityFrameworkStores()
.AddDefaultTokenProviders().AddRoleManager>()
.AddUserManager>();
5.Add a DbContextFactory implement IDesignTimeDbContextFactory, because EF Core may not be able to migrate.
public class DbContextDesignTimeFactory: IDesignTimeDbContextFactory
{
public ApplicationDbContext CreateDbContext(string[] args)
{
DbContextOptionsBuilder builder = new DbContextOptionsBuilder();
var connectionString = arg[0];
builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
return new ApplicationDbContext(builder.Options);
}
}
6.Database migrate
How to use JWT?
1.Configurate JWT
"JwtTokenOption": {
"Issuer": "ChenLi",
"Audience": "EveryOne",
"IssuerSigningKey": "ChenLi$%%^&%*!&^@*GUH976&^^&T*u34",
"AccessTokenExpiresMinutes": "30"
}
2.Create a option
public class JwtTokenOption
{
public const string JwtKey = "JwtTokenOption";
public string Issuer { get; set; }
public string Audience { get; set; }
public string IssuerSigningKey { get; set; }
public int AccessTokenExpiresMinutes { get; set; }
}
3.Add JwtTokenOption Configuration
builder.Services.Configure(builder.Configuration.GetSection(JwtTokenOption.JwtKey));
4.Install JWTBearer NuGet package
Microsoft.AspNetCore.Authentication.JwtBearer
5.Add JwtBearer to Authentication
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
var jwtTokenOption = builder.Configuration.GetSection(JwtTokenOption.JwtKey).Get();
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = jwtTokenOption.Issuer,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtTokenOption.IssuerSigningKey)),
ValidateAudience = true,
ValidAudience = jwtTokenOption.Audience,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(1)
};
options.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
6.Add Class to create Token
public class TokenHelper(IOptionsSnapshot jwtTokenOption) : ITokenHelper
{
public JwtToken CreateToken(T entity) where T : class
{
List claims = new List();
foreach (var item in entity.GetType().GetProperties())
{
object obj = item.GetValue(entity);
string value = "";
if (obj != null)
{
value = obj.ToString();
}
claims.Add(new Claim(item.Name, value));
}
return CreateTokenString(claims);
}
public JwtToken CreateToken(Dictionary KeyValuePairs)
{
List claims = new List();
foreach (var item in KeyValuePairs)
{
claims.Add(new Claim(item.Key, item.Value));
}
return CreateTokenString(claims);
}
private JwtToken CreateTokenString(IEnumerable claims)
{
DateTime expires = DateTime.Now.AddHours(jwtTokenOption.Value.AccessTokenExpiresMinutes);
var token = new JwtSecurityToken(
issuer: jwtTokenOption.Value.Issuer,
audience: jwtTokenOption.Value.Audience,
claims: claims,
notBefore: DateTime.Now,
expires: expires,
signingCredentials: new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtTokenOption.Value.IssuerSigningKey)),
SecurityAlgorithms.HmacSha256
)
);
return new JwtToken()
{
TokenStr = new JwtSecurityTokenHandler().WriteToken(token),
Expires = expires
};
}
}
7.return token to client
[HttpPost]
public async Task Login(String username, String password)
{
ResponseModel response = new ResponseModel();
var user = await userManager.FindByNameAsync(username);
if (user == null)
{
response.Code = 401;
response.Message = "Invalid username or password";
return Unauthorized(response);
}
var checkPassword = await userManager.CheckPasswordAsync(user, password);
Dictionary dir = new Dictionary()
{
{ "username", user.UserName },
};
response.Code = 200;
response.Message = "Success";
response.TokenInfo = tokenHelper.CreateToken(dir);
return Ok(response);
}
8.Add [Authorize] to action or controller, Header must have jwt or will be 401
Headers:
Authorization Bearer
[HttpPost]
[Authorize]
public async Task SendRestPasswordToken(string username)
{
}