提交
This commit is contained in:
parent
12a0958e51
commit
4482fe4272
@ -120,3 +120,291 @@ options.UseOracle(builder.Configuration.GetConnectionString("OracleDbContext")))
|
||||
builder.Services.AddDbContext<SqlServerDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("SqlServerDbContext")));
|
||||
```
|
||||
|
||||
### 2.5 使用JWT进行授权与认证
|
||||
|
||||
安装NuGet包
|
||||
|
||||
`Microsoft.AspNetCore.Authentication.JwtBearer`
|
||||
|
||||

|
||||
|
||||
`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);
|
||||
}
|
||||
```
|
||||
|
||||
访问登录接口
|
||||
|
||||

|
||||
|
||||
访问需要认证的接口,需要把Token放在请求头中,如果不携带Token,访问则报401
|
||||
|
||||

|
||||
|
||||
请求头Key 为 Authorization
|
||||
|
||||
访问成功
|
||||
|
||||

|
||||
|
||||
## 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`
|
||||
|
||||
异常拦截器
|
||||
|
||||
@ -10,3 +10,7 @@ ALTER DATABASE ACT_DEV COLLATE Chinese_PRC_CI_AS;
|
||||
ALTER DATABASE ACT_DEV SET MULTI_USER;
|
||||
```
|
||||
|
||||
## 精度标度
|
||||
|
||||
精度指数字的位数,标度指小数点后的位数。例如,123.45,精度是5,标度是2,decimal(5, 2)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user