2022-12-06 17:41:24 +08:00

12 KiB
Raw Blame History

title, date, author, top_img
title date author top_img
ASP.Net 6 2021-03-23 10:30:31 文永达 https://gcore.jsdelivr.net/gh/volantis-x/cdn-wallpaper/abstract/67239FBB-E15D-4F4F-8EE8-0F1C9F3C4E7C.jpeg

ASP.Net 6

1. 部署到Docker

1.1 安装.Net SDK 6.0环境

sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm
sudo yum install dotnet-sdk-6.0
dotnet --info

1.2 Visual Studio添加Docker支持

image-20221121144928205

1.3 Linux下构建Docker镜像

docker image build -f ./XiaodaERP/Dockerfile -t aspnetcore .
docker images

1.4 运行Docker镜像

docker run --name=aspnetcore -p 9001:80 -d aspnetcore
docker ps
cd /usr/local/jenkins_home/workspace/XiaodaERP_NetCore
echo $PWD
docker image build -f ./XiaodaERP/Dockerfile -t xiaodaerp/netcore .
docker images 
docker run --name xiaodaerp/netcore -p 7274:80 -d xiaodaerp/netcore

2. 顶级语句配置Program.cs

2.1 取消默认JSON首字母小写命名

builder.Services.AddControllers().AddJsonOptions(options => {
    options.JsonSerializerOptions.PropertyNamingPolicy = null;
});

2.2 Json序列化时忽略属性为null的值

builder.Services.AddControllers().AddJsonOptions(options => {
    options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});

2.3 使用Autofac自动注入Service

通过NuGet包管理器 安装NuGet包

image-20221130161234399

image-20221130161319595

Autofac

Autofac.Extensions.DependencyInjection

Autofac.Extras.DynamicProxy

新建ServiceAutofac.cs

using System.Reflection;

namespace XiaodaERP
{
    public class ServiceAutofac
    {
        /// <summary>
        /// 获取程序集名称
        /// </summary>
        /// <returns></returns>
        public static string GetAssemblyName()
        {
            return Assembly.GetExecutingAssembly().GetName().Name;
        }
    }
}

Program.cs配置

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
    Assembly assembly = Assembly.Load(ServiceAutofac.GetAssemblyName());//注入Service程序集 可以是其他程序集
    builder.RegisterAssemblyTypes(assembly)
    .AsImplementedInterfaces()
    .InstancePerDependency();
});

2.4 注入Entity Framework Core 6 DbContext上下文

builder.Services.AddDbContext<OracleDbContext>(options =>
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

image-20221206130808039

appsettings.json配置文件中配置

"Authentication": {
    "SecretKey": "nadjhfgkadshgoihfkajhkjdhsfaidkuahfhdksjaghidshyaukfhdjks",
    "Issuer": "www.xiaoda",
    "Audience": "www.xiaoda"
 }

Program.cs顶级语句配置

// 使用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工具类

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;
        }
    }
}

在登录方法中加入

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]注解,注意登录不能加

[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

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

image-20221206132042533

请求头Key 为 Authorization

访问成功

image-20221206132124913

3. 面向切面编程(AOP)

三大拦截器

AuthorizeAttribute

认证拦截器

ActionFilterAttribute

方法拦截器

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);
            }


        }
        
    }
}

接口上使用

[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

异常拦截器