Change Default Page in Web API project .net core 6 MVC - api

I have ASP.net core **WebAPI ** project after that I create Scaffolded item witch Identity inside this project. How can I change Default page to Identity/page/login.cshtml instead of ~/swagger/index.html
Thanks
change default page from ~/swagger/index.html to Identity/page/login.cshtml
Thanks
my Code here
AppUser.cs
public class AppUser: IdentityUser <int>
{
public string FullName { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
}
program.cs
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});
AppDbContext.cs
public class AppDbContext : IdentityDbContext<AppUser, IdentityRole<int>, int>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
...........................................
}
_LoginPartial.cshtml
#using Claim.Data.Entities
#using Microsoft.AspNetCore.Identity
#inject SignInManager<AppUser> SignInManager
#inject UserManager<AppUser> UserManager
When I Test to click to Login to go to Login Page
error:
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.SignInManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' while attempting to activate 'XXXXXXX.Areas.Identity.Pages.Account.LoginModel'.

hi have fixed the problem. I have to change the Login.cshtmal.sc file.
However I got problem Authentication, cannot login
SignInManager.IsSignedIn(User) <- return claims = 0
_loginPatial.cshtml
#using Microsoft.AspNetCore.Identity
#inject SignInManager<IdentityUser> SignInManager
#inject UserManager<IdentityUser> UserManager
<ul class="navbar-nav">
#if (SignInManager.IsSignedIn(User))
{
<li class="nav-item">
<a id="manage" class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello #UserManager.GetUserName(User)!</a>
</li>
<li class="nav-item">
<form id="logoutForm" class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="#Url.Action("Index", "Home", new { area = "" })">
<button id="logout" type="submit" class="nav-link btn btn-link text-dark">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" id="register" asp-area="Identity" asp-page="/Account/Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" id="login" asp-area="Identity" asp-page="/Account/Login">Login</a>
</li>
}
</ul>
Login.cshtml.cs
if (result.Succeeded) <------ true
public async Task<IActionResult> OnPostAsync(string? returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
..............................
program.cs
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddRazorPages();
builder.Services.AddDbContext<AppDbContext>(opt =>
{
opt.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
builder.Services.AddIdentity<IdentityUser, IdentityRole>().AddDefaultTokenProviders()
.AddEntityFrameworkStores<AppDbContext>();
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Constants.SecretKey)),
ValidateAudience = true,
ValidIssuer = Constants.Issuer,
ValidAudience = Constants.Audience,
RequireExpirationTime = true,
};
});
builder.Services.AddScoped<IUserClaimService, UserClaimServices>();
builder.Services.AddSingleton<IEmailSender, EmailSender>();
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});
//builder.Services.AddMvc().AddRazorPagesOptions(options =>
//{
// options.Conventions.AddAreaPageRoute("Identity", "/Account/Login", "");
//}
// );
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

Related

Validation Context is always NULL

I have implemented a custom validation attribute to check column uniqueness. I want to check if the provided value already exists in the database or not.
Here is my code:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class UniqueAttribute : ValidationAttribute
{
public UniqueAttribute()
{
}
public override bool RequiresValidationContext => true;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return ValidationResult.Success;
}
}
the validationContext in IsValid method always returns null. How it can be fixed?
Startup.cs : ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddScoped<IClaimsTransformation, ClaimsTransformation>();
RegisterRepository(services);
RegisterServices(services);
RegisterAutoMapper(services);
services.AddControllersWithViews()
.AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddRazorPages();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
Model class :
public class Category
{
[Unique]
public string Name { get; set; }
public string Description { get; set; }
}
Below is an example to check if the provided value already exists in the database or not, you can refer to it.
UniqueAttribute:
public class UniqueAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
var context = (MvcMovieContext)validationContext.GetService(typeof(MvcMovieContext));//change the MvcMovieContext to your DbContext
if (!context.Movie.Any(a => a.Company == value.ToString()))
{
return ValidationResult.Success;
}
return new ValidationResult("Company exists");
}
}
Movie:
public class Movie
{
[Unique]
public string Company { get; set; }
}
Create view:
#model MvcMovie.Models.Movie
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Company" class="control-label"></label>
<input asp-for="Company" class="form-control" />
<span asp-validation-for="Company" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
result:

ASP.NET Core localize .cs file in Razor Pages

There is a project on ASP.NET 5.0 with Identity.
Need help in how to translate messages in .cs files Razor Page.
Startup.cs looks like that
namespace localizeTest
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; });
services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix).AddDataAnnotationsLocalization();
services.Configure<RequestLocalizationOptions>(
opt =>
{
var suppoortedCulteres = new List<CultureInfo>
{
new CultureInfo("ru"),
new CultureInfo("en")
};
opt.DefaultRequestCulture = new RequestCulture("ru");
opt.SupportedCultures = suppoortedCulteres;
opt.SupportedUICultures = suppoortedCulteres;
}
);
services.AddDNTCaptcha(options =>
{
options.UseCookieStorageProvider();
});
string connection = Configuration["ConnectionStrings:DefaultConnection"];
ServerVersion vesrion = ServerVersion.AutoDetect(connection);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(connection, vesrion));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseRequestLocalization(app.ApplicationServices.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
In the Resources folder created two files:
/Areas/Identity/Pages/Account/Login.en.resx
/Areas/Identity/Pages/Account/Login.ru.resx
Sample page
Areas/Identity/Pages/Account/Login.cshtml
#page
#model LoginModel
#inject Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer localizer
#{
ViewData["Title"] = localizer["Login"];
}
<div class="container">
<div class="row h-100">
<div class="col-12 col-md-10 mx-auto my-auto">
<div class="card auth-card">
<div class="card-body">
<h1 class="mb-4">#ViewData["Title"]</h1>
<h4 class="pb-2">#localizer["Welcome"]</h4>
<form id="account" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email">#localizer["Email"]</label>
<input asp-for="Input.Email" class="form-control" placeholder="#localizer["YourEmail"]" required="">
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password">#localizer["Password"]</label>
<input asp-for="Input.Password" class="form-control" placeholder="#localizer["YourPassword"]" required="">
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input class="custom-control-input" asp-for="Input.RememberMe">
<label class="custom-control-label" asp-for="Input.RememberMe">#localizer["RememberMe"]</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">#localizer["SignIn"]</button>
</div>
<div class="form-group">
<p>
<a id="forgot-password" asp-page="./ForgotPassword">#localizer["ForgotPass"]</a>
</p>
<p>
<a asp-page="./Register" asp-route-returnUrl="#Model.ReturnUrl">#localizer["ЗарегестрироватьсяКакНовый"]</a>
</p>
<p>
<a id="resend-confirmation" asp-page="./ResendEmailConfirmation">#localizer["EmailConf"]</a>
</p>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
#section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Good, localize in Page View work it!
But, localize in Page Model not work.
File Areas/Identity/Pages/Account/Login.cshtml.cs
namespace localizeTest.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LoginModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
private readonly IStringLocalizer<LoginModel> _stringLocalizer;
public LoginModel(SignInManager<IdentityUser> signInManager,
ILogger<LoginModel> logger,
UserManager<IdentityUser> userManager,
IStringLocalizer<LoginModel> stringLocalizer)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_stringLocalizer = stringLocalizer;
}
[BindProperty]
public InputModel Input { get; set; }
public IList<AuthenticationScheme> ExternalLogins { get; set; }
public string ReturnUrl { get; set; }
[TempData]
public string ErrorMessage { get; set; }
public class InputModel
{
[Display(Name = "Email")]
[Required(ErrorMessage = "{0} is required")]
[EmailAddress]
public string Email { get; set; }
[Display(Name = "Password")]
[Required(ErrorMessage = "{0} is required")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "RememberMe")]
public bool RememberMe { get; set; }
}
public async Task OnGetAsync(string returnUrl = null)
{
if (!string.IsNullOrEmpty(ErrorMessage))
{
ModelState.AddModelError(string.Empty, ErrorMessage);
}
returnUrl ??= Url.Content("~/Books/List");
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/Books/List");
string WrongLoggin = _stringLocalizer["НеВерныйЛогин"].Value;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, WrongLoggin);
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}
}
}
How to translate text in .cs files, how to make it work?
[Display(Name = "How Translate With Text?")]
[Required(ErrorMessage = "How {0} Translate with Text?")]
Img Login Ru
Img Login En
I tried examples as for pages of controllers.
Created resources with the name LoginModel+InnerModel.en.resx and LoginModel+InnerModel.ru.resx.
But it did't give results.
P.S. Sorry for Google translate, but i need help.
P.S.2. Localization made on the example of this video
First you need to add AddDataAnnotationsLocalization in your Stratup,
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddRazorPages().AddDataAnnotationsLocalization();
Then you need to name your resource file like
Areas.Identity.Pages.Account.LoginModel+InputModel.en-US.resx
For any nested model in LoginModel, you need to use + instead of .
For the details you can see the doc:
DataAnnotations localization.

Controller not executing code (Blazor server-side)

My Goal Create a simple login form in order to authenticate and authorize the user in my Blazor Server-side app with Cookie Authentication.
My Issue Everything works... The EditForm passes the values to my Controller. The Controller validates the usercredentials. Then runs HttpContext.SignInAsync(claims) and returns Ok().
But the Cookie is not passed and the user is not Authenticate either.
What I have done
1. The EditForm, passes the userinputs to the DisplayLoginModel() on a ValidSubmit.
<div class="row">
<div class="col-8">
<EditForm Model="#userLogin" OnValidSubmit="OnValidLogin">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="mb-4 row">
<p class="col-sm-4 font-weight-bold">Email</p>
<div class="col-sm-8">
<InputText #bind-Value="userLogin.Email" class="form-control" />
</div>
</div>
<div class="mb-4 row">
<p class="col-sm-4 font-weight-bold">Password</p>
<div class="col-sm-8">
<InputText #bind-Value="userLogin.Password" class="form-control" />
</div>
</div>
<button class="btn btn-outline-primary col-sm-4" type="submit"><strong>Login EditForm</strong></button>
</EditForm>
</div>
</div>
2. The OnValidLogin Sends a request to the Form Controller
public DisplayLoginModel userLogin = new DisplayLoginModel();
private async Task OnValidLogin()
{
var requestMessage = new HttpRequestMessage()
{
Method = new HttpMethod("POST"),
RequestUri = new Uri("https://localhost:44370/Form"),
Content = JsonContent.Create(userLogin)
};
var client = httpfac.CreateClient();
var response = await client.SendAsync(requestMessage);
}
3. The Controller gets the user credentials from the displayloginModel and validets Ok().
[HttpPost]
public async Task<ActionResult> Post(DisplayLoginModel _userLogin)
{
if (_userLogin.Email == "this#Email.com")
{
ClaimsIdentity claimsIdentity = new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.Role, "ActiveUser")
}, "auth");
ClaimsPrincipal claims = new ClaimsPrincipal(claimsIdentity);
await HttpContext.SignInAsync(claims);
return Ok();
}
else
{
return BadRequest();
}
}
4. Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
services.AddHttpContextAccessor();
services.AddAuthentication("Cookies").AddCookie(options =>
{
options.SlidingExpiration = true;
});
services.AddRazorPages();
services.AddServerSideBlazor();
}
And
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
Why is the Controller not signing the user in, what am I missing?
An image of the solution structure is seen right below:
Because Blazor Server uses websockets (Blazor circuits) to render the UI while on the controller, await HttpContext.SignInAsync(claims); returns a cookie header so the browser can be authorized on next page load. This means you are actually being authenticated server-side but not from the client-side as you have not reloaded the page context to update the cookies. There is a reason why the default Identity login uses MVC architecture for the authentication process. :)
My suggestion, switch to API-based authentication/authorization or use a traditional login in flow.

How do you add Identity server 4.0 as an external provider?

It looks like all of the sources talk about adding external providers INTO Identity Server 4, not using Identity Server 4 AS an external provider.
My startup.cs has this line for Facebook authentication:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddFacebook(facebookOptions =>
{
facebookOptions.AppId = "<appId>";
facebookOptions.AppSecret = "<appSecret>";
facebookOptions.SaveTokens = true;
})
I have a button on my login page:
<a class="btn btn-primary"
asp-action="ExternalLogin"
asp-route-provider="Facebook"
asp-route-returnUrl="">
Facebook
</a>
Which leads to:
[HttpPost]
[HttpGet]
[AllowAnonymous]
public IActionResult ExternalLogin(string provider, string returnUrl = null)
{
// Request a redirect to the external login provider.
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
Which all works.
I also have an Identity Server 4.0 server setup and I would like to use it as just another external provider.
services
.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddFacebook(facebookOptions =>
{
facebookOptions.AppId = "<appId>";
facebookOptions.AppSecret = "<appSecret>";
facebookOptions.SaveTokens = true;
})
.AddIdentityServer(identityServerOptions=> //Doesn't exist? or Does it?
{
identityServerOptions.AppId = "<appId>";
identityServerOptions.AppSecret = "<appSecret>";
identityServerOptions.SaveTokens = true;
})
How do I add identity server as an external auth provider?
**UPDATE: **
From This site
#if (Model.ExternalProviders.Any())
{
<div class="row">
<div class="panel-body">
<ul class="list-inline">
#foreach (var provider in Model.ExternalProviders)
{
<li>
<a class="btn btn-default"
asp-action="ExternalLogin"
asp-route-provider="#provider.AuthenticationScheme"
asp-route-returnUrl="#Model.ReturnUrl">
#provider.DisplayName
</a>
</li>
}
</ul>
</div>
</div>
}
It looks like the provider is the same as the Authentication Scheme
Identityserver is a certified OpenId Connect provider, so you can use just:
.AddOpenIdConnect(authenticationScheme, displayName, options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Authority = "<base-path-of-your-external-IS>";
options.ClientSecret = "<appSecret>";
options.ClientId = "<appId>";
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
}

Simple Role Manager and authorization In ASP.NET MVC 5 without using Identity(CustomRoleProvider)

Custom Role Provider and authorization without using Identity in ASP.NET MVC 5
Here is the Roles Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace SN.Helios.Portal.Controllers
{
[Authorize(Roles = "Admin")]
public class RolesController : Controller
{
// GET: Roles
public ActionResult Index()
{
var context = new ApplicationDbContext();
var rolelist = context.Roles.OrderBy(r => r.RoleName).ToList().Select(rr =>
new SelectListItem { Value = rr.RoleName.ToString(), Text = rr.RoleName }).ToList();
ViewBag.Roles = rolelist;
var userlist = context.Employees.OrderBy(u => u.FullName).ToList().Select(uu =>
new SelectListItem { Value = uu.FullName.ToString(), Text = uu.FullName }).ToList();
ViewBag.Users = userlist;
ViewBag.Message = "";
return View();
}
// GET: /Roles/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Roles/Create
[HttpPost]
public ActionResult Create(Role role)
{
try
{
var context = new ApplicationDbContext();
context.Roles.Add(role);
context.SaveChanges();
ViewBag.Message = "Role created successfully !";
return RedirectToAction("Index");
}
catch
{
return View();
}
}
public ActionResult Delete(string RoleName)
{
var context = new ApplicationDbContext();
var thisRole = context.Roles.Where(r => r.RoleName.Equals(RoleName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
context.Roles.Remove(thisRole);
context.SaveChanges();
return RedirectToAction("Index");
}
//
// GET: /Roles/Edit/5
public ActionResult Edit(string roleName)
{
var context = new ApplicationDbContext();
var thisRole = context.Roles.Where(r => r.RoleName.Equals(roleName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
return View(thisRole);
}
//
// POST: /Roles/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Role role)
{
try
{
var context = new ApplicationDbContext();
context.Entry(role).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
// Adding Roles to a user
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RoleAddToUser(string UserName, string RoleName)
{
var context = new ApplicationDbContext();
if (context == null)
{
throw new ArgumentNullException("context", "Context must not be null.");
}
Employee user = context.Employees.Where(u => u.FullName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
Role role = context.Roles.Where(u => u.RoleName.Equals(RoleName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
AssignUserRole assignUserRole = new AssignUserRole
{
EmployeeId = user.EmployeeID,
RoleId = role.RoleID
};
var EmpRoleToAdd = (from emprole in context.AssignUserRoles
where emprole.EmployeeId == user.EmployeeID && emprole.RoleId == role.RoleID
select emprole).FirstOrDefault();
if (EmpRoleToAdd == null)
{
context.AssignUserRoles.Add(assignUserRole);
context.SaveChanges();
ViewBag.Message = "Role created successfully !";
}
else
{
ViewBag.Message = " This Role already exists for this user !";
}
// Repopulate Dropdown Lists
var rolelist = context.Roles.OrderBy(r => r.RoleName).ToList().Select(rr => new SelectListItem { Value = rr.RoleName.ToString(), Text = rr.RoleName }).ToList();
ViewBag.Roles = rolelist;
var userlist = context.Employees.OrderBy(u => u.FullName).ToList().Select(uu =>
new SelectListItem { Value = uu.FullName.ToString(), Text = uu.FullName }).ToList();
ViewBag.Users = userlist;
return View("Index");
}
//Getting a List of Roles for a User
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult GetRoles(string UserName)
{
if (!string.IsNullOrWhiteSpace(UserName))
{
var context = new ApplicationDbContext();
Employee user = context.Employees.Where(u => u.FullName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var roles = user.AssignUserRoles.Select(u => u.Role).Select(u => u.RoleName).ToArray();
ViewBag.RolesForThisUser = roles;
// Repopulate Dropdown Lists
var rolelist = context.Roles.OrderBy(r => r.RoleName).ToList().Select(rr => new SelectListItem { Value = rr.RoleName.ToString(), Text = rr.RoleName }).ToList();
ViewBag.Roles = rolelist;
var userlist = context.Employees.OrderBy(u => u.FullName).ToList().Select(uu =>
new SelectListItem { Value = uu.FullName.ToString(), Text = uu.FullName }).ToList();
ViewBag.Users = userlist;
ViewBag.Message = "Roles retrieved successfully !";
}
return View("Index");
}
//Deleting a User from A Role
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DeleteRoleForUser(string UserName, string RoleName)
{
var context = new ApplicationDbContext();
Employee user = context.Employees.Where(u => u.FullName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
Role role = context.Roles.Where(u => u.RoleName.Equals(RoleName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var EmpRoleToDelete = (from emprole in context.AssignUserRoles
where emprole.EmployeeId == user.EmployeeID && emprole.RoleId == role.RoleID
select emprole).FirstOrDefault();
if (EmpRoleToDelete != null)
{
context.AssignUserRoles.Remove(EmpRoleToDelete);
context.SaveChanges();
ViewBag.Message = "Role removed from this user successfully !";
}
else
{
ViewBag.Message = "This user doesn't belong to selected role.";
}
// Repopulate Dropdown Lists
var rolelist = context.Roles.OrderBy(r => r.RoleName).ToList().Select(rr => new SelectListItem { Value = rr.RoleName.ToString(), Text = rr.RoleName }).ToList();
ViewBag.Roles = rolelist;
var userlist = context.Employees.OrderBy(u => u.FullName).ToList().Select(uu =>
new SelectListItem { Value = uu.FullName.ToString(), Text = uu.FullName }).ToList();
ViewBag.Users = userlist;
return View("Index");
}
}
}
Create Index View for Roles Controller
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_mainView.cshtml";
}
<div class="row col-sm-12 col-lg-12 col-md-12">
<h1 style="text-align:center">Role Manager</h1>
<br />
</div>
<div class="row col-sm-12 col-lg-12 col-md-12">
<div class="col-sm-6 col-lg-6 col-md-6">
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Role List</h4>
</div>
<div class="panel-body">
<table class="table table-striped table-hover col-sm-6 col-lg-6 col-md-6 ">
#foreach (var role in ViewBag.Roles)
{
<tr>
<td class="col-sm-1 col-lg-5 col-md-5">
<strong>#role.Text </strong>
</td>
<td class="col-sm-1 col-lg-1 col-md-1">
<span onclick="return confirm('Are you sure to delete?')">Delete</span> |
#Html.ActionLink("Edit", "Edit", new { roleName = #role.Text })
</td>
</tr>
}
</table>
</div> <!-- End Panel Body-->
</div> <!-- End Panel -->
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Create A New Role</h4>
</div>
<div class="panel-body">
#using (Html.BeginForm("Create", "Roles", new { #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div>
Role name: #Html.TextBox("RoleName")
<input type="submit" value="Save" class="btn-primary" />
</div>
}
</div> <!--End Panel Body-->
</div> <!--End Panel-->
</div> <!--End First Column-->
<div class="col-sm-6 col-lg-6 col-md-6">
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Add a Role to a User</h4>
</div>
<div class="panel-body">
#using (Html.BeginForm("RoleAddToUser", "Roles"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<p>User Name: #Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")</p>
<p>Role Name: #Html.DropDownList("RoleName", (IEnumerable<SelectListItem>)ViewBag.Roles, "Select ...")</p>
<p><input type="submit" value="Save" class="btn-primary" /></p>
}
</div> <!-- End Panel Body-->
</div> <!-- End Panel -->
<div class="panel panel-primary">
<div class="panel-heading">
<h4>List Roles for a User</h4>
</div>
<div class="panel-body">
#using (Html.BeginForm("GetRoles", "Roles"))
{
#Html.AntiForgeryToken()
<p>
User Name: #Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")
<input type="submit" value="Get Roles for this User" class="btn-primary" />
</p>
}
#if (ViewBag.RolesForThisUser != null)
{
<div class="alert-info">
<strong>Roles for this user </strong>
<ol>
#foreach (string s in ViewBag.RolesForThisUser)
{
<li>#s</li>
}
</ol>
</div>
}
</div> <!-- End Panel Body-->
</div> <!-- End Panel -->
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Remove Role from User</h4>
</div>
<div class="panel-body">
#using (Html.BeginForm("DeleteRoleForUser", "Roles"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<p>User Name: #Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")</p>
<p>Role Name: #Html.DropDownList("RoleName", (IEnumerable<SelectListItem>)ViewBag.Roles, "Select ...")</p>
<p><input type="submit" value="Delete this user from Role" class="btn-primary" /></p>
}
</div> <!-- End Panel Body-->
</div> <!-- End Panel -->
</div> <!--End Second Column-->
</div> <!--Overall Page Wrapper-->
<div class="alert-info col-sm-12 col-lg-12 col-md-12">
#ViewBag.Message
</div>
---------------------------------------------------------------------
Create Edit View For Roles Controller
#model yournamespace.Role
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_mainView.cshtml";
}
<h2>Edit Role</h2>
#Html.ActionLink("Return to Role Manager", "Index")
<hr />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.RoleID)
<div>
Role name
</div>
<p>
#Html.TextBoxFor(model => model.RoleName)
</p>
<input type="submit" value="Save" />
}
Create Roles and Assign to the Users
Create Class CustomRoleProvider
Inherit CustomRoleProvider from RoleProvider class as shown below and implement abstract class.Make changes in the classes as shown below
using System;
using System.Linq;
using System.Web.Security;
namespace yournamespace.Models
{
public class CustomRoleProvider : RoleProvider
{
public override string ApplicationName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override void CreateRole(string roleName)
{
throw new NotImplementedException();
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
using (var usersContext = new SNHeliosWork2017Entities())
{
return usersContext.Roles.Select(r => r.RoleName).ToArray();
}
}
public override string[] GetRolesForUser(string username)
{
using (var usersContext = new SNHeliosWork2017Entities())
{
var user = usersContext.Employees.SingleOrDefault(u => u.FullName == username);
if (user == null)
return new string[] { };
return user.AssignUserRoles == null ? new string[] { } :
user.AssignUserRoles.Select(u => u.Role).Select(u => u.RoleName).ToArray();
}
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override bool IsUserInRole(string username, string roleName)
{
using (var usersContext = new SNHeliosWork2017Entities())
{
var user = usersContext.Employees.SingleOrDefault(u => u.FullName == username);
if (user == null)
return false;
return user.AssignUserRoles != null && user.AssignUserRoles.Select(
u => u.Role).Any(r => r.RoleName == roleName);
}
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
}
}
In web.config add the following code within system.web tag
<system.web>
<sessionState mode="InProc" timeout="20" cookieless="false"></sessionState>
<authentication mode="Forms">
<forms loginUrl="~/Home/LogIn" defaultUrl="~/" timeout="20" slidingExpiration="true"/>
</authentication>
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<clear/>
<add name="CustomRoleProvider" type="MyProject.Models.CustomRoleProvider" />
</providers>
</roleManager>
</system.web>
The first thing to note is that I have set the enabled attribute to true so that the framework enables the role manager. Then you have to specify the defaultProvider attribute, which is used to identify the default provider if a number of providers are specified. But in this case, I am going to have only one provider CustomRoleProvider, still the default provider has to be specified. This is contained within the providers element. The clear element is used to clear all the providers stored for this application earlier, for example the default providers. Then I have defined the custom role provider by specifying the name "CustomRoleProvider", which was used in the defaultProvider attribute. This contains a number of attributes. The most important one is the type attribute where the fully-qualified name of the custom role provider is specified (MyProject.Models.CustomRoleProvider), followed by the assembly containing this type (MyProject) and the version. Note that only the type name is required and others are optional if the type is contained within the same assembly - the web application itself. Other attributes are self-explanatory and I am not going to bore you with all these details!
Use authorize attribute to authorize controllers
As,
[Authorize(Roles = "Admin")]
public class RolesController : Controller
{
}