I am working on a web app that needs to integrate with an existing user database. I would still like to use the [Authorize]
attributes, but I don't want to use the Identity framework. If I did want to use the Identity framework I would add something like this in the startup.cs file:
services.AddIdentity<ApplicationUser, IdentityRole>(options => { options.Password.RequireNonLetterOrDigit = false; }).AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();
I'm assuming I have to add something else there, and then create some kind of class that implements a specific interface? Can somebody point me in the right direction? I'm using RC1 of of asp.net 5 right now.
In this article. Authentication is the process of determining a user's identity. Authorization is the process of determining whether a user has access to a resource. In ASP.NET Core, authentication is handled by the authentication service, IAuthenticationService, which is used by authentication middleware.
Custom authentication, which includes both username/password tokens and custom tokens, is an integral part of the proxy service definition. When a proxy service is exported, any configuration of custom tokens is included in the jar file.
From what I learned after several days of research, Here is the Guide for ASP .Net Core MVC 2.x Custom User Authentication
In Startup.cs
:
Add below lines to ConfigureServices
method :
public void ConfigureServices(IServiceCollection services) { services.AddAuthentication( CookieAuthenticationDefaults.AuthenticationScheme ).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.LoginPath = "/Account/Login"; options.LogoutPath = "/Account/Logout"; }); services.AddMvc(); // authentication services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; }); services.AddTransient( m => new UserManager( Configuration .GetValue<string>( DEFAULT_CONNECTIONSTRING //this is a string constant ) ) ); services.AddDistributedMemoryCache(); }
keep in mind that in above code we said that if any unauthenticated user requests an action which is annotated with [Authorize]
, they well force redirect to /Account/Login
url.
Add below lines to Configure
method :
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); app.UseDatabaseErrorPage(); } else { app.UseExceptionHandler(ERROR_URL); } app.UseStaticFiles(); app.UseAuthentication(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: DEFAULT_ROUTING); }); }
Create your UserManager
class that will also manage login and logout. it should look like below snippet (note that i'm using dapper):
public class UserManager { string _connectionString; public UserManager(string connectionString) { _connectionString = connectionString; } public async void SignIn(HttpContext httpContext, UserDbModel user, bool isPersistent = false) { using (var con = new SqlConnection(_connectionString)) { var queryString = "sp_user_login"; var dbUserData = con.Query<UserDbModel>( queryString, new { UserEmail = user.UserEmail, UserPassword = user.UserPassword, UserCellphone = user.UserCellphone }, commandType: CommandType.StoredProcedure ).FirstOrDefault(); ClaimsIdentity identity = new ClaimsIdentity(this.GetUserClaims(dbUserData), CookieAuthenticationDefaults.AuthenticationScheme); ClaimsPrincipal principal = new ClaimsPrincipal(identity); await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal); } } public async void SignOut(HttpContext httpContext) { await httpContext.SignOutAsync(); } private IEnumerable<Claim> GetUserClaims(UserDbModel user) { List<Claim> claims = new List<Claim>(); claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id().ToString())); claims.Add(new Claim(ClaimTypes.Name, user.UserFirstName)); claims.Add(new Claim(ClaimTypes.Email, user.UserEmail)); claims.AddRange(this.GetUserRoleClaims(user)); return claims; } private IEnumerable<Claim> GetUserRoleClaims(UserDbModel user) { List<Claim> claims = new List<Claim>(); claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id().ToString())); claims.Add(new Claim(ClaimTypes.Role, user.UserPermissionType.ToString())); return claims; } }
Then maybe you have an AccountController
which has a Login
Action that should look like below :
public class AccountController : Controller { UserManager _userManager; public AccountController(UserManager userManager) { _userManager = userManager; } [HttpPost] public IActionResult LogIn(LogInViewModel form) { if (!ModelState.IsValid) return View(form); try { //authenticate var user = new UserDbModel() { UserEmail = form.Email, UserCellphone = form.Cellphone, UserPassword = form.Password }; _userManager.SignIn(this.HttpContext, user); return RedirectToAction("Search", "Home", null); } catch (Exception ex) { ModelState.AddModelError("summary", ex.Message); return View(form); } } }
Now you are able to use [Authorize]
annotation on any Action
or Controller
.
Feel free to comment any questions or bug's.
Creating custom authentication in ASP.NET Core can be done in a variety of ways. If you want to build off existing components (but don't want to use identity), checkout the "Security" category of docs on docs.asp.net. https://docs.asp.net/en/latest/security/index.html
Some articles you might find helpful:
Using Cookie Middleware without ASP.NET Identity
Custom Policy-Based Authorization
And of course, if that fails or docs aren't clear enough, the source code is at https://github.com/dotnet/aspnetcore/tree/master/src/Security which includes some samples.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With