目录
一:说明
鉴权:是指验证你是否登录,你登录后的身份是什么。
授权:是指验证你的权限,你的身份有没有权限做这个事。
二:传统鉴权授权的基本配置
Program关键代码:
using Microsoft.AspNetCore.Authentication.Cookies;
//表示整个应用程序,调用CreateBuilder方法创建一个WebApplicationBuilder对象。
var builder = WebApplication.CreateBuilder(args);
//向管道容器添加注册中间件
//添加注册控制器视图中间件
builder.Services.AddControllersWithViews();
//添加注册Session中间件
builder.Services.AddSession();
//添加注册鉴权中间件
builder.Services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultForbidScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, option =>
{
//鉴权授权失败跳转登录视图
option.LoginPath = "/Home/Login";
//没有权限跳转指定视图
option.AccessDeniedPath = "/Home/NoAuthority";
});
//配置管道容器中间件,构造WebApplication实例
var app = builder.Build();
//判断是否是开发模式
if (!app.Environment.IsDevelopment())
{
//向管道中添加中间件,该中间件将捕获异常、记录异常、重置请求路径并重新执行请求。
app.UseExceptionHandler("/Shared/Error");
//向管道中添加用于使用HSTS的中间件,该中间件添加了Strict Transport Security标头。默认值为30天
app.UseHsts();
}
//向管道添加Session中间件
app.UseSession();
//向管道添加用于将HTTP请求重定向到HTTPS的中间件。
app.UseHttpsRedirection();
//向管道添加为当前请求路径启用静态文件服务
app.UseStaticFiles();
//向管道添加路由配置中间件
app.UseRouting();
//向管道添加鉴权中间件
app.UseAuthentication();
//向管道添加授权中间件
app.UseAuthorization();
//向管道添加默认路由中间件
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
//向管道添加启动应用程序中间件
app.Run();
User关键代码:
using System.ComponentModel.DataAnnotations;
namespace Study_ASP.NET_Core_MVC.Models
{
public class User
{
public int UserId { get; set; }
[Display(Name="账号")]
public string? UserName { get; set; }
public string? Account { get; set; }
[Display(Name = "密码")]
public string? UserPwd { get; set; }
[DataType(DataType.EmailAddress)]
[Display(Name = "邮箱")]
public string? UserEmail { get; set;}
public DateTime LoginTime { get; set; }
}
}
Home控制器代码:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Study_ASP.NET_Core_MVC.Models;
using System.Diagnostics;
using System.Security.Claims;
namespace Study_ASP.NET_Core_MVC.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
/// <summary>
/// Get请求
/// 默认授权
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize]
public IActionResult Index()
{
var user = HttpContext.User;
return View();
}
/// <summary>
/// Get请求
/// </summary>
/// <returns></returns>
public IActionResult NoAuthority()
{
return View();
}
/// <summary>
/// Get请求
/// 登录视图
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult Login()
{
return View();
}
/// <summary>
/// Post请求
/// 登录视图
/// </summary>
/// <param name="UserName"></param>
/// <param name="UserPwd"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> Login(string UserName,string UserPwd)
{
if ("VinCente".Equals(UserName) && "123456".Equals(UserPwd)){
var claims = new List<Claim>()
{
new Claim("UserId","1"),
new Claim(ClaimTypes.Role,"Admin"),
new Claim(ClaimTypes.Role,"User"),
new Claim(ClaimTypes.Name,$"{UserName}---来自于Cookies"),
new Claim(ClaimTypes.Email,$"VinCente@123.com"),
new Claim("Password",UserPwd),
new Claim("Account","Administrator"),
new Claim("Role","admin"),
new Claim("QQ","7257624")
};
ClaimsPrincipal userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "UserMessage"));
HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
{
//过期时间30分钟
ExpiresUtc = DateTime.UtcNow.AddSeconds(30)
}).Wait();
var user = HttpContext.User;
return base.Redirect("/Home/Index");
}
else
{
base.ViewBag.Message = "账号或密码错误";
}
return await Task.FromResult<IActionResult>(View());
}
}
}
视图代码:
@using Study_ASP.NET_Core_MVC.Models;
@model User
@{
ViewBag.Title = "登录";
}
<h2>登录</h2>
<div class="row">
<div class="col-md-8">
<section id="loginForm">
@using (Html.BeginForm("Login", "Home", new { sid = "123", Account = "VinCente" },
FormMethod.Post, true, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<hr />
@Html.ValidationSummary(true)
<div class="mb-3 row">
@Html.LabelFor(m => m.UserName, new { @class = "col-sm-1 col-form-label" })
<div class="col-md-6">
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control", @placeholder="请输入账号" })
</div>
</div>
<div class="mb-3 row">
@Html.LabelFor(m => m.UserPwd, new { @class = "col-md-1 control-label" })
<div class="col-md-6">
@Html.PasswordFor(m => m.UserPwd, new { @class = "form-control",@placeholder="请输入密码" })
</div>
</div>
<div class="mb-3 row">
<div class="col-md-offset-2 col-md-6">
<button type="submit" class="btn btn-primary mb-3">登录</button>
@base.ViewBag.Message
</div>
</div>
}
</section>
</div>
</div>
三 :角色配置说明
标记多个角色授权控制器代码:
/// <summary>
/// Get请求
/// 默认授权
/// 授权给角色为Admin的用户,可以访问
/// 授权给角色为User的用户,可以访问
/// 授权给角色为Tracher的用户,不可以访问,VinCente用户没有Teacher授权
/// 同时授权给用户多个角色Roles时,必须同时满足角色Roles,才可以访问
/// </summary>
/// <returns></returns>
[HttpGet]
//[Authorize]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Roles = "Admin")]
//[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Roles = "User")]
//[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Roles = "Teacher")]
public IActionResult Index()
{
var user = HttpContext.User;
return View();
}
标记单个角色授权控制器代码:
/// <summary>
/// Get请求
/// 默认授权
/// 授权给角色为Admin和User的用户,包含其中一个角色,可以访问
/// 授权给角色为User和Teacher的用户,包含其中一个角色,可以访问
/// 授权给角色为Tracher和Admin的用户,包含其中一个角色,可以访问
/// 授权给角色为System和Teacher的用户,不包含其中一个角色,不可以访问
/// </summary>
/// <returns></returns>
[HttpGet]
//[Authorize]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Roles = "Admin,User")]
//[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Roles = "User,Teacher")]
//[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Roles = "Teacher,Admin")]
//[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Roles = "System,Teacher")]
public IActionResult Index()
{
var user = HttpContext.User;
return View();
}
四:策略鉴权授权
Program关键代码:
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Security.Claims;
//表示整个应用程序,调用CreateBuilder方法创建一个WebApplicationBuilder对象。
var builder = WebApplication.CreateBuilder(args);
//向管道容器添加注册中间件
//添加注册控制器视图中间件
builder.Services.AddControllersWithViews();
//添加注册Session中间件
builder.Services.AddSession();
//添加注册鉴权授权中间件
builder.Services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultForbidScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, option =>
{
//鉴权授权失败跳转登录视图
option.LoginPath = "/Home/Login";
//没有权限跳转指定视图
option.AccessDeniedPath = "/Home/NoAuthority";
});
//添加注册策略鉴权授权中间件
builder.Services.AddAuthorization(option =>
{
//注册一个为RolePolicy的策略授权
option.AddPolicy("RolePolicy", policyBuilder =>
{
//必须包含某个角色
//policyBuilder.RequireRole("Teacher");
//必须包含Account条件
//policyBuilder.RequireClaim("Account");
//必须包含指定条件
policyBuilder.RequireAssertion(context =>
{
return context.User.HasClaim(c => c.Type == ClaimTypes.Role) && context.User.Claims.First(c => c.Type.Equals(ClaimTypes.Role)).Value == "Admin" && context.User.Claims.Any(c => c.Type == ClaimTypes.Name);
});
//policyBuilder.AddRequirements(new QQEmailRequirement());
});
});
//配置管道容器中间件,构造WebApplication实例
var app = builder.Build();
//判断是否是开发模式
if (!app.Environment.IsDevelopment())
{
//向管道中添加中间件,该中间件将捕获异常、记录异常、重置请求路径并重新执行请求。
app.UseExceptionHandler("/Shared/Error");
//向管道中添加用于使用HSTS的中间件,该中间件添加了Strict Transport Security标头。默认值为30天
app.UseHsts();
}
//向管道添加Session中间件
app.UseSession();
//向管道添加用于将HTTP请求重定向到HTTPS的中间件。
app.UseHttpsRedirection();
//向管道添加为当前请求路径启用静态文件服务
app.UseStaticFiles();
//向管道添加路由配置中间件
app.UseRouting();
//向管道添加鉴权中间件
app.UseAuthentication();
//向管道添加授权中间件
app.UseAuthorization();
//向管道添加默认路由中间件
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
//向管道添加启动应用程序中间件
app.Run();
控制器代码:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Study_ASP.NET_Core_MVC.Models;
using System.Diagnostics;
using System.Security.Claims;
namespace Study_ASP.NET_Core_MVC.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
/// <summary>
/// Get请求
/// 策略授权
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Policy = "RolePolicy")]
public IActionResult Index()
{
var user = HttpContext.User;
return View();
}
/// <summary>
/// Get请求
/// </summary>
/// <returns></returns>
public IActionResult NoAuthority()
{
return View();
}
/// <summary>
/// Get请求
/// 登录视图
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult Login()
{
return View();
}
/// <summary>
/// Post请求
/// 登录视图
/// </summary>
/// <param name="UserName"></param>
/// <param name="UserPwd"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> Login(string UserName, string UserPwd)
{
if ("VinCente".Equals(UserName) && "123456".Equals(UserPwd))
{
var claims = new List<Claim>()
{
new Claim("UserId","1"),
new Claim(ClaimTypes.Role,"Admin"),
new Claim(ClaimTypes.Role,"User"),
new Claim(ClaimTypes.Name,$"{UserName}---来自于Cookies"),
new Claim(ClaimTypes.Email,$"VinCente@123.com"),
new Claim("Password",UserPwd),
new Claim("Account","Administrator"),
new Claim("Role","admin"),
new Claim("QQ","7257624")
};
ClaimsPrincipal userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "UserMessage"));
HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
{
//过期时间30分钟
ExpiresUtc = DateTime.UtcNow.AddSeconds(30)
}).Wait();
var user = HttpContext.User;
return base.Redirect("/Home/Index");
}
else
{
base.ViewBag.Message = "账号或密码错误";
}
return await Task.FromResult<IActionResult>(View());
}
}
}
五:策略鉴权授权Requirement扩展
IUserService代码:
namespace Study_ASP.NET_Core_MVC.Models
{
public interface IUserService
{
public bool Validata(string userId, string qq);
}
}
UserService代码:
namespace Study_ASP.NET_Core_MVC.Models
{
public class UserService: IUserService
{
public bool Validata(string userId, string qq)
{
//在这里去链接数据库去校验这个QQ是否正确
return true;
}
}
}
QQEmailRequirement代码:
using Microsoft.AspNetCore.Authorization;
namespace Study_ASP.NET_Core_MVC.Models
{
public class QQEmailRequirement:IAuthorizationRequirement
{
}
}
QQHandler代码:
using Microsoft.AspNetCore.Authorization;
namespace Study_ASP.NET_Core_MVC.Models
{
public class QQHandler:AuthorizationHandler<QQEmailRequirement>
{
//初始化构造函数
private IUserService _UserService;
public QQHandler(IUserService userService)
{
this._UserService = userService;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, QQEmailRequirement requirement)
{
if (context.User.Claims.Count() == 0)
{
return Task.CompletedTask;
}
string userId = context.User.Claims.First(c => c.Type == "UserId").Value;
string qq = context.User.Claims.First(c => c.Type == "QQ").Value;
if (_UserService.Validata(userId, qq))
{
//验证通过
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
Program关键代码:
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Study_ASP.NET_Core_MVC.Models;
using System.Security.Claims;
//表示整个应用程序,调用CreateBuilder方法创建一个WebApplicationBuilder对象。
var builder = WebApplication.CreateBuilder(args);
//向管道容器添加注册中间件
//添加注册控制器视图中间件
builder.Services.AddControllersWithViews();
//添加注册Session中间件
builder.Services.AddSession();
//添加注册鉴权授权中间件
builder.Services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultForbidScheme = CookieAuthenticationDefaults.AuthenticationScheme;
option.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, option =>
{
//鉴权授权失败跳转登录视图
option.LoginPath = "/Home/Login";
//没有权限跳转指定视图
option.AccessDeniedPath = "/Home/NoAuthority";
});
//添加注册策略鉴权授权中间件
builder.Services.AddAuthorization(option =>
{
//注册一个为RolePolicy的策略授权
option.AddPolicy("RolePolicy", policyBuilder =>
{
//必须包含某个角色
//policyBuilder.RequireRole("Teacher");
//必须包含Account条件
//policyBuilder.RequireClaim("Account");
//必须包含指定条件
policyBuilder.RequireAssertion(context =>
{
return context.User.HasClaim(c => c.Type == ClaimTypes.Role) && context.User.Claims.First(c => c.Type.Equals(ClaimTypes.Role)).Value == "Admin" && context.User.Claims.Any(c => c.Type == ClaimTypes.Name);
});
policyBuilder.AddRequirements(new QQEmailRequirement());
});
});
//添加注册策略鉴权授权中间件外部文件
builder.Services.AddTransient<IUserService, UserService>();
builder.Services.AddTransient<IAuthorizationHandler, QQHandler>();
//配置管道容器中间件,构造WebApplication实例
var app = builder.Build();
//判断是否是开发模式
if (!app.Environment.IsDevelopment())
{
//向管道中添加中间件,该中间件将捕获异常、记录异常、重置请求路径并重新执行请求。
app.UseExceptionHandler("/Shared/Error");
//向管道中添加用于使用HSTS的中间件,该中间件添加了Strict Transport Security标头。默认值为30天
app.UseHsts();
}
//向管道添加Session中间件
app.UseSession();
//向管道添加用于将HTTP请求重定向到HTTPS的中间件。
app.UseHttpsRedirection();
//向管道添加为当前请求路径启用静态文件服务
app.UseStaticFiles();
//向管道添加路由配置中间件
app.UseRouting();
//向管道添加鉴权中间件
app.UseAuthentication();
//向管道添加授权中间件
app.UseAuthorization();
//向管道添加默认路由中间件
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
//向管道添加启动应用程序中间件
app.Run();
控制器代码:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Study_ASP.NET_Core_MVC.Models;
using System.Diagnostics;
using System.Security.Claims;
namespace Study_ASP.NET_Core_MVC.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
/// <summary>
/// Get请求
/// 策略授权
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Policy = "RolePolicy")]
public IActionResult Index()
{
var user = HttpContext.User;
return View();
}
/// <summary>
/// Get请求
/// </summary>
/// <returns></returns>
public IActionResult NoAuthority()
{
return View();
}
/// <summary>
/// Get请求
/// 登录视图
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult Login()
{
return View();
}
/// <summary>
/// Post请求
/// 登录视图
/// </summary>
/// <param name="UserName"></param>
/// <param name="UserPwd"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> Login(string UserName, string UserPwd)
{
if ("VinCente".Equals(UserName) && "123456".Equals(UserPwd))
{
var claims = new List<Claim>()
{
new Claim("UserId","1"),
new Claim(ClaimTypes.Role,"Admin"),
new Claim(ClaimTypes.Role,"User"),
new Claim(ClaimTypes.Name,$"{UserName}---来自于Cookies"),
new Claim(ClaimTypes.Email,$"VinCente@123.com"),
new Claim("Password",UserPwd),
new Claim("Account","Administrator"),
new Claim("Role","admin"),
new Claim("QQ","7257624")
};
ClaimsPrincipal userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "UserMessage"));
HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
{
//过期时间30分钟
ExpiresUtc = DateTime.UtcNow.AddSeconds(30)
}).Wait();
var user = HttpContext.User;
return base.Redirect("/Home/Index");
}
else
{
base.ViewBag.Message = "账号或密码错误";
}
return await Task.FromResult<IActionResult>(View());
}
}
}
总结
使用传统鉴权授权的基本配置,验证用户是否登录,如果当前没有用户信息直接跳转至登录视图,在Program文件中配置,登录之后可以正常访问被标记为[Authorize]的控制器或控制器方法,由于控制器代码中HttpPost的Login方法中写明用户角色。搭配角色使用,在控制器或控制器方法上标记可以访问该控制器或方法的角色,除了当前标记的角色外,都不可以访问该控制器或控制器方法。搭配策略使用,在特殊的控制器或控制器上标记可以访问该控制器或方法的策略名称,符合该策略的用户可以访问。不能访问的用户直接跳转至Home控制器下的NoAuthority方法中的视图,提醒用户没有权限访问该方法。通过使用AddRequirements扩展,可以自定义验证用户鉴权授权。