This commit is contained in:
wenyongda 2022-12-06 17:41:24 +08:00
parent 12a0958e51
commit 4482fe4272
2 changed files with 292 additions and 0 deletions

View File

@ -120,3 +120,291 @@ options.UseOracle(builder.Configuration.GetConnectionString("OracleDbContext")))
builder.Services.AddDbContext<SqlServerDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("SqlServerDbContext"))); builder.Services.AddDbContext<SqlServerDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("SqlServerDbContext")));
``` ```
### 2.5 使用JWT进行授权与认证
安装NuGet包
`Microsoft.AspNetCore.Authentication.JwtBearer`
![image-20221206130808039](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221206130808039.png)
`appsettings.json`配置文件中配置
```json
"Authentication": {
"SecretKey": "nadjhfgkadshgoihfkajhkjdhsfaidkuahfhdksjaghidshyaukfhdjks",
"Issuer": "www.xiaoda",
"Audience": "www.xiaoda"
}
```
`Program.cs`顶级语句配置
```c#
// 使用Autofac自动注入Service
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
Assembly assembly = Assembly.Load(ServiceAutofac.GetAssemblyName());//注入Service程序集 可以是其他程序集
builder.RegisterAssemblyTypes(assembly)
.AsImplementedInterfaces()
.InstancePerDependency();
// 在IOC容器中注入
// 用于Jwt的各种操作
builder.RegisterType<JwtSecurityTokenHandler>().InstancePerLifetimeScope();
// 支持泛型存入Jwt
builder.RegisterType<TokenHelper>().InstancePerLifetimeScope();
});
//JWT认证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
//取出私钥
var secretByte = Encoding.UTF8.GetBytes(builder.Configuration["Authentication:SecretKey"]);
options.TokenValidationParameters = new TokenValidationParameters()
{
//验证发布者
ValidateIssuer = true,
ValidIssuer = builder.Configuration["Authentication:Issuer"],
//验证接受者
ValidateAudience = true,
ValidAudience = builder.Configuration["Authentication:Audience"],
//验证是否过期
ValidateLifetime = true,
//验证私钥
IssuerSigningKey = new SymmetricSecurityKey(secretByte)
};
});
// 顺序不能颠倒
// 你是谁 授权
app.UseAuthentication();
// 你可以干什么 验证
app.UseAuthorization();
```
新建`TokenHelper.cs`工具类
```c#
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Security.Claims;
using System.Text;
using XiaodaERP.Models;
namespace XiaodaERP.Utils
{
public class TokenHelper
{
private readonly IConfiguration _configuration;
private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
public TokenHelper(IConfiguration configuration, JwtSecurityTokenHandler jwtSecurityTokenHandler)
{
this._configuration = configuration;
this._jwtSecurityTokenHandler = jwtSecurityTokenHandler;
}
public static string? Token { get; set; }
// 生成Token
public string CreateJwtToken<T>(T user)
{
// 生成JWT
// Header选择签名算法
var signingAlogorithm = SecurityAlgorithms.HmacSha256;
// Payload存放用户信息放用户ID用户名
var claimList = this.CreateClaimList(user);
//Signature
//取出私钥并以utf8编码字节输出
var secretByte = Encoding.UTF8.GetBytes(_configuration["Authentication:SecretKey"]);
//使用非对称算法对私钥进行加密
var signingKey = new SymmetricSecurityKey(secretByte);
//使用HmacSha256来验证加密后的私钥生成数字签名
var signingCredentials = new SigningCredentials(signingKey, signingAlogorithm);
//生成Token
var Token = new JwtSecurityToken(
issuer: _configuration["Authentication:Issuer"], //发布者
audience: _configuration["Authentication:Audience"], //接收者
claims: claimList, //存放的用户信息
notBefore: DateTime.UtcNow, //发布时间
expires: DateTime.UtcNow.AddMinutes(30), //有效期设置为1天
signingCredentials //数字签名
);
//生成字符串token
var TokenStr = new JwtSecurityTokenHandler().WriteToken(Token);
return TokenStr;
}
// 获取Token Payload信息
public T GetToken<T>(string token)
{
Type t = typeof(T);
object obj = Activator.CreateInstance(t);
var b = _jwtSecurityTokenHandler.ReadJwtToken(token);
foreach (var item in b.Claims)
{
PropertyInfo propertyInfo = t.GetProperty(item.Type);
if (propertyInfo != null && propertyInfo.CanRead)
{
propertyInfo.SetValue(obj, item.Value, null);
}
}
return (T)obj;
}
// 根据类生成Token 断言列表
private List<Claim> CreateClaimList<T>(T authUser)
{
var Class = typeof(T);
List<Claim> claimList = new();
foreach (var item in Class.GetProperties())
{
// 不将PassWord放入Token中
if (item.Name == "PassWord")
{
continue;
}
// 将UserName属性名重命名为username存入Token中
if (item.Name == "UserName")
{
claimList.Add(new Claim("username", Convert.ToString(item.GetValue(authUser))));
continue;
}
claimList.Add(new Claim(item.Name, Convert.ToString(item.GetValue(authUser))));
}
return claimList;
}
}
}
```
在登录方法中加入
```c#
public ViewUser Login(string UserName, string PassWord)
{
var res = _sqlServerDbContext.Users.Include(user => user.Role).FirstOrDefault(x => x.UserName == UserName);
if (res != null)
{
if (res.PassWord == Md5Encoding(PassWord))
{
// 生成JWT
var TokenStr = _tokenHelper.CreateJwtToken(res);
var config = new MapperConfiguration(cfg => cfg.CreateMap<User, ViewUser>()
.ForMember(d => d.username, opt => opt.MapFrom(src => src.UserName))
.AfterMap((src, des) => des.Roles = new Role[1] { src.Role })
.AfterMap((src, des) => des.Token = "bearer " + TokenStr) // 需要加上bearer
.AfterMap((src, des) => des.HomePath = "/dashboard/analysis")
.AfterMap((src, des) => des.password = null));
var mapper = config.CreateMapper();
return mapper.Map<ViewUser>(res);
}
}
return null;
}
```
WebAPI 需要认证的加上`[Authorize]`注解,注意登录不能加
```c#
[AuthFilter]
[HttpPost(Name = "login")]
public ResultUtil Login(ViewUser viewUser) =>
ResultUtil.ok(_userService.Login(viewUser.username, viewUser.password));
// 需要认证的API
[Authorize]
[AuthFilter]
[HttpGet(Name = "getUserInfo")]
public ResultUtil GetUserInfo()
{
Token = HttpContext.Request.Headers["Authorization"];
Token = Token.Split(" ")[1];
TokenHelper.Token = Token;
ViewUser us = _tokenHelper.GetToken<ViewUser>(Token);
return ResultUtil.ok(us);
}
```
访问登录接口
![image-20221206131847333](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221206131847333.png)
访问需要认证的接口需要把Token放在请求头中如果不携带Token访问则报401
![image-20221206132042533](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221206132042533.png)
请求头Key 为 Authorization
访问成功
![image-20221206132124913](https://markdownhexo.oss-cn-hangzhou.aliyuncs.com/img/image-20221206132124913.png)
## 3. 面向切面编程(AOP)
三大拦截器
`AuthorizeAttribute`
认证拦截器
`ActionFilterAttribute`
方法拦截器
```c#
using Microsoft.AspNetCore.Mvc.Filters;
namespace XiaodaERP.Attributes
{
public class AuthFilter : ActionFilterAttribute
{
// 方法请求后
public override void OnActionExecuted(ActionExecutedContext context)
{
// 获取请求Host
Console.WriteLine(context.HttpContext.Request.Host);
// 获取请求方法
Console.WriteLine(context.HttpContext.Request.Method);
// 获取请求Url
Console.WriteLine(context.HttpContext.Request.Path);
}
// 方法请求时
public override void OnActionExecuting(ActionExecutingContext context)
{
//Console.WriteLine(context.ActionArguments.ToList());
foreach (var kv in context.ActionArguments)
{
Console.WriteLine("{0}, : ,{1}", kv.Key, kv.Value);
}
}
}
}
```
接口上使用
```c#
[AuthFilter]
[HttpPost(Name = "login")]
public ResultUtil Login(ViewUser viewUser) =>
ResultUtil.ok(_userService.Login(viewUser.username, viewUser.password));
[Authorize]
[AuthFilter] // 注解为拦截器类名
[HttpGet(Name = "getUserInfo")]
public ResultUtil GetUserInfo()
{
Token = HttpContext.Request.Headers["Authorization"];
Token = Token.Split(" ")[1];
TokenHelper.Token = Token;
ViewUser us = _tokenHelper.GetToken<ViewUser>(Token);
return ResultUtil.ok(us);
}
```
`ExceptionFilterAttribute`
异常拦截器

View File

@ -10,3 +10,7 @@ ALTER DATABASE ACT_DEV COLLATE Chinese_PRC_CI_AS;
ALTER DATABASE ACT_DEV SET MULTI_USER; ALTER DATABASE ACT_DEV SET MULTI_USER;
``` ```
## 精度标度
精度指数字的位数标度指小数点后的位数。例如123.45精度是5标度是2decimal(5, 2)