DotNet Core WebApi项目搭建

DotNet Core WebApi项目搭建

环境搭建

Core执行过程

在这里插入图片描述

IIS发布

https://dotnet.microsoft.com/download/

1 需要安装运行时和托管拥绑包
地址:https://dotnet.microsoft.com/download/dotnetcore/thank-you/runtime-aspnetcore-3.1.2-windows-hosting-bundle-installer
2 必须要发布不能直接执行系统的根目录
3 需要安装Core的运行时环境
4 指定为无代码托管

  • 确认启用了WWW服务
    在这里插入图片描述
  • 配置Core的运行时环境,在IIS的模块中添加AspNetCoreModuleV2
    在这里插入图片描述
  • 设置无托代码(Core最新版本可以不设)
    在这里插入图片描述

WebApi启动方式

  • WebApi启动方式,使用CMD切换到DLL文件目录下通过命令可以运行WebApi
dotnet Test.CoreWebApi.dll --urls="http://*:8004"--ip="127.0.0.1"--port= 8004

配置Swagger

CoreWebApi-Swagger配置
1.nuget安装:Swashbuckle.AspNetCore程序包;
2.注册Swagger服务;
3.在中间件中使用Swagger;

  • 在Startup.cs类中注册Swagger服务并增加中间件

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using Microsoft.OpenApi.Models;
    
    namespace Test.Core.WebApi
    {
        /// <summary>
        /// Core 项目中导出都是IOC + DI
        /// </summary>
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
            /// <summary>
            /// 被运行时调用的  还有什么?
            /// 执行且只执行一次;
            /// </summary>
            /// <param name="services"></param>
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                #region 注册Swagger服务 
                services.AddSwaggerGen(s =>
                {
                    //注册 Swagger
                    s.SwaggerDoc("V1", new OpenApiInfo()
                    {
                        Title = "test",//显示名称
                        Version = "version-01",//显示版本
                        Description = "朝夕教育Api学习"//显示标题
                    });
                });
                #endregion
                services.AddControllers();
            }
    
            // 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();
                } 
                //使用Swagger中间件
                app.UseSwagger();
                app.UseSwaggerUI(s =>
                {
                    s.SwaggerEndpoint("/swagger/V1/swagger.json", "test1");//不同版本的文件,test1与文件名对应可以进行切换。
                });
                //使用中间件
                app.UseRouting();
                app.UseAuthorization();          
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
            }
        }
    }
    
  • 访问路径:localhost:XXXX/swagger/index.html 注意大小写

  • 在launchSettings.json文件中修改起始页面

    {
      "$schema": "http://json.schemastore.org/launchsettings.json",
      "iisSettings": {
        "windowsAuthentication": false,
        "anonymousAuthentication": true,
        "iisExpress": {
          "applicationUrl": "http://localhost:50786",
          "sslPort": 0
        }
      },
      "profiles": {
        "IIS Express": {
          "commandName": "IISExpress",
          "launchBrowser": true,
          "launchUrl": "swagger/index.html",//设置Swagger为初始页面
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        },
        "Test.Core.WebApi": {
          "commandName": "Project",
          "launchBrowser": true,
          "launchUrl": "weatherforecast",
          "applicationUrl": "http://localhost:5000",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        }
      }
    }
    

    Nginx负载均衡

在这里插入图片描述

Nginx环境

1.下载Nginx安装包:http://nginx.org/en/download.html
2.启动Nginx服务器;建议下载稳定版;
3.可以查看任务管理器;会出现Nginx进程

Nginx配置负载均衡

listen 9090; #设计Nginx的默认端口
server_name 9090.max.com;#注释:这里转发的设置
location /{
	#root html;
	#index index.html index.htm;
	proxypass http://webApi;//设置代理转发;转发到服务器列表
}
服务器列表:
upstream webApi {
	server localhost:8001;
	server localhost:8002;
	server localhost:8003;
  • Nginx配置文件内容~\nginx-1.16.1\conf\nginx.conf

    #user  nobody;
    worker_processes  1;
    
    #error_log  logs/error.log;
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;
    
    #pid        logs/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
    
        #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
        #                  '$status $body_bytes_sent "$http_referer" '
        #                  '"$http_user_agent" "$http_x_forwarded_for"';
    
        #access_log  logs/access.log  main;
    
        sendfile        on;
        #tcp_nopush     on;
    
        #keepalive_timeout  0;
        keepalive_timeout  65;
    
        #gzip  on;
        
    	#注释:这里转发的设置
        upstream webApi {
    	server localhost:8001;
    	server localhost:8002;
    	server localhost:8003;
         }
    
    
        server {
            listen       9090;
            server_name  9090.max.com;#注释:这里转发的设置
    
    
            #charset koi8-r;
    
            #access_log  logs/host.access.log  main;
    
            location / {
                  proxy_pass http://webApi; #注释:这里转发的设置
            }
    
            #error_page  404              /404.html;
    
            # redirect server error pages to the static page /50x.html
            #
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
    
            # proxy the PHP scripts to Apache listening on 127.0.0.1:80
            #
            #location ~ \.php$ {
            #    proxy_pass   http://127.0.0.1;
            #}
    
            # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
            #
            #location ~ \.php$ {
            #    root           html;
            #    fastcgi_pass   127.0.0.1:9000;
            #    fastcgi_index  index.php;
            #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
            #    include        fastcgi_params;
            #}
    
            # deny access to .htaccess files, if Apache's document root
            # concurs with nginx's one
            #
            #location ~ /\.ht {
            #    deny  all;
            #}
        }
    
    
        # another virtual host using mix of IP-, name-, and port-based configuration
        #
        #server {
        #    listen       8000;
        #    listen       somename:8080;
        #    server_name  somename  alias  another.alias;
    
        #    location / {
        #        root   html;
        #        index  index.html index.htm;
        #    }
        #}
    
    
        # HTTPS server
        #
        #server {
        #    listen       443 ssl;
        #    server_name  localhost;
    
        #    ssl_certificate      cert.pem;
        #    ssl_certificate_key  cert.key;
    
        #    ssl_session_cache    shared:SSL:1m;
        #    ssl_session_timeout  5m;
    
        #    ssl_ciphers  HIGH:!aNULL:!MD5;
        #    ssl_prefer_server_ciphers  on;
    
        #    location / {
        #        root   html;
        #        index  index.html index.htm;
        #    }
        #}
    
    }
    

Log4Net集成

1.Nuget引入log4net/ Microsoft.Extensions.Logging.Log4Net.AspNetCore
2.增加配置log4net配置文件
3.使用配置文件

logging.AddFilter("System", LogLevel.Warning);
logging.AddFilter("Microsoft", LogLevel. Warning);
logging.AddLog4Net("ConfigFile/log4net.Config”);
  • Log4Net的配置文件(log4net.Config),配置文件需要设置为始终复制,否则发布后无法找到。

    <?xml version="1.0" encoding="utf-8"?>
    <log4net>
    	<!-- Define some output appenders -->
    	<appender name="rollingAppender" type="log4net.Appender.RollingFileAppender">
    		<file value="log\log.txt" />
    
    		<!--追加日志内容-->
    		<appendToFile value="true" />
    
    		<!--防止多线程时不能写Log,官方说线程非安全-->
    		<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    
    		<!--可以为:Once|Size|Date|Composite-->
    		<!--Composite为Size和Date的组合-->
    		<rollingStyle value="Composite" />
    
    		<!--当备份文件时,为文件名加的后缀-->
    		<datePattern value="yyyyMMdd.TXT" />
    
    		<!--日志最大个数,都是最新的-->
    		<!--rollingStyle节点为Size时,只能有value个日志-->
    		<!--rollingStyle节点为Composite时,每天有value个日志-->
    		<maxSizeRollBackups value="20" />
    
    		<!--可用的单位:KB|MB|GB-->
    		<maximumFileSize value="3MB" />
    
    		<!--置为true,当前最新日志文件名永远为file节中的名字-->
    		<staticLogFileName value="true" />
    
    		<!--输出级别在INFO和ERROR之间的日志-->
    		<filter type="log4net.Filter.LevelRangeFilter">
    			<param name="LevelMin" value="ALL" />
    			<param name="LevelMax" value="FATAL" />
    		</filter> 
    		<!--必须结合起来用,第一个只过滤出WARN,第二个拒绝其它其它日志输出-->
    		<!--
    		<filter type="log4net.Filter.LevelMatchFilter">
    			<param name="LevelToMatch" value="WARN" />
    		</filter>
    		<filter type="log4net.Filter.DenyAllFilter" />-->
    
    		<layout type="log4net.Layout.PatternLayout">
    			<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
    		</layout>
    	</appender> 
    	<!-- levels: OFF > FATAL > ERROR > WARN > INFO > DEBUG  > ALL -->
    	<root>
    		<priority value="ALL"/>
    		<level value="ALL"/>
    		<appender-ref ref="rollingAppender" />
    	</root>
    </log4net>
    
  • 在Program.cs中进行注册

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    
    namespace Test.Core.WebApi
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
            /// <summary>
            /// Builder标准的建造者模式
            /// </summary>
            /// <param name="args"></param>
            /// <returns></returns>
            public static IHostBuilder CreateHostBuilder(string[] args)
            {
                return Host.CreateDefaultBuilder(args)
                    //Log4net注册
                .ConfigureLogging(logging => //支持IOC  控制反转
                {
                    logging.AddFilter("System", LogLevel.Warning);
                    logging.AddFilter("Microsoft", LogLevel.Warning);
                    logging.AddLog4Net();//配置文件默认在根目录下,如果不在此目录下应使用重载方法
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
            }
        }
    }
    
  • 将Logger对象注入至控制器中进行调用

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    namespace Test.Core.WebApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class SecondController : ControllerBase
        {
            private ILogger<SecondController> _Logger = null;
            public SecondController(ILogger<SecondController> logger)
            {
                this._Logger = logger;
                _Logger.LogInformation("SecondController 被构造。。。。");
            }
            [Route("Get")]
            [HttpGet]
            public string Get()
            {
                _Logger.LogInformation("SecondController.Get 被调用");
                return "this is Test--003";
            }
        }
    }
    

AOP-Filter

AOP(面向切面编程)

在这里插入图片描述

IResoureFilter做缓存例子

AOP在Core中通过Filter来实现,Core-Filter VS Asp.Net-Filter

Asp.Net WebApiCore WehApi
授权过滤器IAuthorizationFilter授权过滤器AuthorizeAttribute
异常过滤器lExceptionFilter异常过滤器lExceptionFilter, lAsyncExceptionFilter
方法过滤器lActionFilter方法过滤器ActionFilterAttribute, lActionFilter, lAsyncActionFilter
资源过滤器lResourceFilter
结果过滤器ResultFilterAttribute, IResultFilter, lAsyncResultFilter
  • Asp.net的Filter是在控制器实例化以后调用的。NetCoreWeiApi中的IResourceFilter是在控制器对象创建前先执行了OnResourceExecuting方法,在控制器返回数据时又执行OnResourceExecuted方法,适合做缓存使用。

在这里插入图片描述
以下是IResourceFilter做缓存应用的示例代码

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Test.Core.WebApi.Utility
{
    public class CustomResourceFilterAttribute : Attribute, IResourceFilter
    {
        private static Dictionary<string, object> dictionaryCache = new Dictionary<string, object>();
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            string key = context.HttpContext.Request.Path.ToString();
            if (dictionaryCache.ContainsKey(key))
            {
                context.Result = dictionaryCache[key] as ObjectResult;    //Result 短路器
            } 
        }
        public void OnResourceExecuted(ResourceExecutedContext context)//当Api的数据发生了变化时应将缓存清除
        {
            ///把数据存储缓存;
            //Key---path;
            string key = context.HttpContext.Request.Path.ToString();
            ObjectResult objectResult = context.Result as ObjectResult;
            dictionaryCache[key] = objectResult;         
        }
    }
}

IActionFilter做日志的例子(搭配Log4Net)

  • 创建特性类继承于Attrbute并实现IActionFilter接口

  • 将Logger对象依赖注入到特性类中

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Test.Core.WebApi.Utility
    {
        public class CustomActionFilterAttribute : Attribute, IActionFilter //ActionFilterAttribute //IActionFilter,//IAsyncActionFilter
        {
    
            private ILogger<CustomActionFilterAttribute> _Logger = null;
    		//依赖注入logger
            public CustomActionFilterAttribute(ILogger<CustomActionFilterAttribute> logger)
            {
                _Logger = logger;
            } 
    
            /// <summary>
            /// 方法执行后
            /// </summary>
            /// <param name="context"></param>
            public void OnActionExecuted(ActionExecutedContext context)
            {  
                var result = context.Result;
                ObjectResult objectResult= result as ObjectResult; 
                var resultLog = $"{DateTime.Now} 调用 {context.RouteData.Values["action"]} api 完成;执行结果:{Newtonsoft.Json.JsonConvert.SerializeObject(objectResult.Value)}"; 
                _Logger.LogInformation(resultLog); 
            }
    
            /// <summary>
            /// 方法执行前
            /// </summary>
            /// <param name="context"></param>
            public void OnActionExecuting(ActionExecutingContext context)
            { 
                var actionLog = $"{DateTime.Now} 开始调用 {context.RouteData.Values["action"]} api;参数为:{Newtonsoft.Json.JsonConvert.SerializeObject(context.ActionArguments)}"; 
                _Logger.LogInformation(actionLog);
                //这里就可以把信息写入到日志中来;       
            }
        }
    }
    
  • 特性注册方法(注意看代码注释)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Test.Core.WebApi.Utility;
    
    namespace Test.Core.WebApi.Controllers
    {
        //能不能注册以后让所有的Api 都生效?
        //Startup.cs中进行注册
        [Route("api/[controller]")]
        [ApiController]
        //2.Filter对控制器下的所有Api生效
        //[ServiceFilter(typeof(CustomActionFilterAttribute))] //需要注册服务
        [ServiceFilter(typeof(CustomControllerActionFilterAttribute))]
        public class FilterController : ControllerBase
        {
            public FilterController()
            {
                Console.WriteLine("FilterController 被构造。。。");
            }    
            //难道每个方法都需要去注册一下吗?
            //1.Filter方法注册  
            [Route("GetInfoByParamter")]
            [HttpGet]
            [CustomActionFilter] //特性的方式标记  只能支持带无参数构造函数的
            [TypeFilter(typeof(CustomActionFilterAttribute))]//不需要注册服务
            [ServiceFilter(typeof(CustomActionFilterAttribute))] //需要注册服务
            [CustomIOCFilterFactory(typeof(CustomActionFilterAttribute))]  //需要注册服务  
            public string GetInfoByParamter(int id,string Name)
            {
                return $"this is Id={id},Name={Name}";
            }
        }
    }
    
  • 注册服务Startup.cs

           // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                #region 注册Swagger服务 
                services.AddSwaggerGen(s =>
                {
                    #region 注册 Swagger
                    s.SwaggerDoc("V1", new OpenApiInfo()
                    {
                        Title = "test",
                        Version = "version-01",
                        Description = "朝夕教育Api学习"
                    });
                    #endregion 
                });
                #endregion           
                services.AddControllers();
                //注册服务,将类放在IOC容器中
                services.AddSingleton<CustomActionFilterAttribute>();
                services.AddSingleton<CustomGlobalActionFilterAttribute>();
                services.AddSingleton<CustomControllerActionFilterAttribute>();
                #region 全局注册Filter
                //3.对所有的方法都生效        
                services.AddMvc(option => {
                    option.Filters.Add(typeof(CustomGlobalActionFilterAttribute));
                });
                #endregion
            }
    
  • 自定义IOC工厂类CustomIOCFilterFactory的代码

    using Microsoft.AspNetCore.Mvc.Filters;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Test.Core.WebApi.Utility
    {
        public class CustomIOCFilterFactoryAttribute : Attribute, IFilterFactory
        {
            private Type _FilterType = null;
            public CustomIOCFilterFactoryAttribute(Type type)
            {
                _FilterType = type;
            }
            public bool IsReusable => true;
    
            /// <summary>
            /// 在Core 中对象的创建 都是通过IOC 容器来创建
            /// </summary>
            /// <param name="serviceProvider"></param>
            /// <returns></returns>
            public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
            {
                return (IFilterMetadata)serviceProvider.GetService(this._FilterType);
            }
        }
    }
    

鉴权JWT

鉴权方式

传统的Seesion-Cookie方式
在这里插入图片描述
基于Token的无状态方式
在这里插入图片描述### JWT介绍

在这里插入图片描述

鉴权中心搭建(CoreWebApi)

  • 控制器代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using Test.Core.AuthenticationCenter.Utility;
    
    namespace Test.Core.AuthenticationCenter.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class AuthenticationController : ControllerBase
        { 
            #region MyRegion
            private ILogger<AuthenticationController> _logger = null;
            private IJWTService _iJWTService = null;
            private readonly IConfiguration _iConfiguration;
            public AuthenticationController(ILoggerFactory factory,
                ILogger<AuthenticationController> logger,
                IConfiguration configuration
                , IJWTService service)
            {
                this._logger = logger;
                this._iConfiguration = configuration;
                this._iJWTService = service;
            }
            #endregion
            [Route("Get")]
            [HttpGet]
            public IEnumerable<int> Get()
            {
                return new List<int>() { 1, 2, 3, 4, 6, 7 };
            }
    
            [Route("Login")]
            [HttpGet]
            public string Login(string name, string password)
            {
                ///这里肯定是需要去连接数据库做数据校验
                if ("Richard".Equals(name) && "123456".Equals(password))//应该数据库
                {
                    string token = this._iJWTService.GetToken(name);
                    return JsonConvert.SerializeObject(new
                    {
                        result = true,
                        token
                    });
                }
                else
                {
                    return JsonConvert.SerializeObject(new
                    {
                        result = false,
                        token = ""
                    });
                }
            }
        }
    }
    
  • JWTService类代码

    using Microsoft.Extensions.Configuration;
    using Microsoft.IdentityModel.Tokens;
    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Tokens.Jwt;
    using System.Linq;
    using System.Security.Claims;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Test.Core.AuthenticationCenter.Utility
    {
        public interface IJWTService
        {
            string GetToken(string UserName);
        }
        /// <summary>
        /// 备注下:代码演示的是对称加密,所以只有一个key,在返回的信息里面是没有的
        /// PPT介绍时,说的是非对称的,那样是把解密key公开的,前面是后台用私钥加密的,
        /// 可以保证别人解密后 拿到的数据  跟前面2部分hash后的结果一致 保证没有篡改
        /// 此外,公钥不是在返回结果,那只是个打比方~
        /// </summary>
        public class JWTService : IJWTService
        {
            private readonly IConfiguration _configuration;
            public JWTService(IConfiguration configuration)
            {
                _configuration = configuration;
            }
    
            public string GetToken(string UserName)
            {
                Claim[] claims = new[]
                {
                   new Claim(ClaimTypes.Name, UserName),
                   new Claim("NickName","Richard"),
                   new Claim("Role","Administrator"),//传递其他信息  
                   new Claim("abc","abccc")
                   //new Claim
                };
                SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SecurityKey"]));
                SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                /**
                 *  Claims (Payload)
                    Claims 部分包含了一些跟这个 token 有关的重要信息。 JWT 标准规定了一些字段,下面节选一些字段:
                    iss: The issuer of the token,token 是给谁的
                    sub: The subject of the token,token 主题
                    exp: Expiration Time。 token 过期时间,Unix 时间戳格式
                    iat: Issued At。 token 创建时间, Unix 时间戳格式
                    jti: JWT ID。针对当前 token 的唯一标识
                    除了规定的字段外,可以包含其他任何 JSON 兼容的字段。
                 * */
                var token = new JwtSecurityToken(
                    issuer: _configuration["issuer"],
                    audience: _configuration["audience"],
                    claims: claims,
                    expires: DateTime.Now.AddMinutes(5),//5分钟有效期
                    signingCredentials: creds);
                string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
                return returnToken;
            }
        }
    }
    
  • DI依赖注入代码

            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddScoped<IJWTService, JWTService>();//IOC DI容器依赖注入
                services.AddControllers();
            }
    
  • 配置文件代码

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      "audience": "http://localhost:10086",
      "issuer": "http://localhost:10086",
      "SecurityKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB"//Token密钥,可以使用私钥加密RSA后
    }
    

客户端(CoreWebApi)

  • 控制器权限验证代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    
    namespace Test.Core.WebApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        [Authorize]//鉴权
        public class AuthorizeController : ControllerBase
        {
            private ILogger<AuthorizeController> _Logger = null;
    
            public AuthorizeController(ILogger<AuthorizeController> logger)
            {
                this._Logger = logger;
                _Logger.LogInformation($"{nameof(AuthorizeController)} 被构造。。。。 ");
            }
    
            [HttpGet]
            [Route("Get")]
            [AllowAnonymous]//跳过鉴权
            public IActionResult Get()
            {
                return new JsonResult(new
                {
                    Data = "这个是OK的,这个Api并没有要求授权!"
    
                });
            }
    
            [HttpGet]
            [Route("GetAuthorizeData")]
           // [Authorize] //Microsoft.AspNetCore.Authorization
            public IActionResult GetAuthorizeData()
            { 
                //读取Token中的信息
              var Name = base.HttpContext.AuthenticateAsync().Result.Principal.Claims.FirstOrDefault(a=>a.Type.Equals("Name"))?.Value;
    
                Console.WriteLine($"this is Name {Name}"); 
                return new JsonResult(new
                {
                    Data = "已授权",
                    Type = "GetAuthorizeData" 
                    //Claims=Newtonsoft.Json.JsonConvert.SerializeObject(Claims)
                });
            }
        }
    }
    
  • Startup.cs中注册服务

            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {                     
                #region JWT鉴权授权
                //1.Nuget引入程序包:Microsoft.AspNetCore.Authentication.JwtBearer 
                //services.AddAuthentication();//禁用  
                var ValidAudience = this.Configuration["audience"];
                var ValidIssuer = this.Configuration["issuer"];
                var SecurityKey = this.Configuration["SecurityKey"];
                services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)  //默认授权机制名称;                                     
                         .AddJwtBearer(options =>
                         {
                             options.TokenValidationParameters = new TokenValidationParameters
                             {
                                 ValidateIssuer = true,//是否验证Issuer
                                 ValidateAudience = true,//是否验证Audience
                                 ValidateLifetime = true,//是否验证失效时间
                                 ValidateIssuerSigningKey = true,//是否验证SecurityKey
                                 ValidAudience = ValidAudience,//Audience
                                 ValidIssuer = ValidIssuer,//Issuer,这两项和前面签发jwt的设置一致  表示谁签发的Token
                                 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey))//拿到SecurityKey
                                 //AudienceValidator = (m, n, z) =>
                                 //{
                                 //    return m != null && m.FirstOrDefault().Equals(this.Configuration["audience"]);
                                 //},//自定义校验规则,可以新登录后将之前的无效 
                             };
                         });
                #endregion
            }
    
  • 注册中间件

            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                //使用中间件
                #region 通过中间件来支持鉴权授权
                app.UseAuthentication();
                #endregion
            }
    

跨域

同源策略

  • 浏览器的同源策略阻止跨域

同源策略(Same Origin Policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略会阻止一个域的JS脚本和另外一个域的内容进行交互。

在这里插入图片描述

解决跨域问题的途径。

在这里插入图片描述

  1. JSONP是基于前端使用特定的标签访问可以绕开浏览器的跨域验证。

  2. 前端网站不直接通过浏览器请求HTTP而是调用一个本地方法,方法中模拟了一个HTTP请求,从而绕开了浏览器。

    • 在Index.cshtml文件url中将Http请求改为一个方法(基于MVC项目演示)
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <div class="text-center">
        <h1 class="display-4">Welcome</h1>
        <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    </div>
      请求数据: <div id="result"></div>
    <script src="~/js/jquery-3.4.1.js" charset="utf-8"></script>
    <script type="text/javascript"> 
            $.ajax({
                type: "Get",
                data: {},
                url: "GetCrossDaminData", //为解决跨域,url中将Http请求改为一个方法
                success: function (result) { 
                    $("#result").text(result);
                }
            }) 
    </script>
    
    • 在HomeController.cs对应的方法中模拟一个HTTP请求
    [HttpGet]
    [Route("GetCrossDaminData")]
    public string GetCrossDaminData()
    {
        //我这里去模拟Http请求获取到数据以后再返回给前端
        string url = "http://localhost:8004/api/CrossDamin/GetCrossDaminData"; 
        using (HttpClient httpClient = new HttpClient())
    	{
        	HttpRequestMessage message = new HttpRequestMessage();
            message.Method = HttpMethod.Get;
            message.RequestUri = new Uri(url);
            var result = httpClient.SendAsync(message).Result;
            string content = result.Content.ReadAsStringAsync().Result;
            return content;
    	}
    }
    
  3. 配置服务器使服务器允许跨域

    • 在响应头中增加Access-Control-Allow-Origin字段

      using Microsoft.AspNetCore.Authorization;
      using Microsoft.AspNetCore.Mvc;
      using Test.Core.WebApi.Utility;
      
      namespace Test.Core.WebApi.Controllers
      {
          [Route("api/[controller]")]
          [ApiController]
          //[CrossDomainFilterAttribute] //通过IActionFilter在响应头中增加Access-Control-Allow-Origin字段,实现跨域
          public class CrossDaminController : ControllerBase
          {
              [HttpGet]
              [Route("GetCrossDaminData")] 
              [CrossDomainFilterAttribute] //通过IActionFilter在响应头中增加Access-Control-Allow-Origin字段,实现跨域
              public string GetCrossDaminData()
              {  
                  //base.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*"); //在响应头中增加Access-Control-Allow-Origin字段,实现跨域
                  return Newtonsoft.Json.JsonConvert.SerializeObject(
                      new { 
                      id=123,
                      Name="开塔克撞火车",
                      Description="这个Api 就是专门用测试跨域问题。。"
                      });
              }       
          }
      }
      
      using Microsoft.AspNetCore.Mvc.Filters;
      using System;
      
      namespace Test.Core.WebApi.Utility
      {
          public class CrossDomainFilterAttribute : Attribute, IActionFilter
          {
              //无论是在OnActionExecuted、OnActionExecuting 来指定跨域都可以;但是两个方法里面不能同时都指定;
              public void OnActionExecuted(ActionExecutedContext context)
              {
                  #region 支持跨域
                  context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
                  #endregion
              }
      
              public void OnActionExecuting(ActionExecutingContext context)
              {
                  //#region 支持跨域
                  //context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
                  //#endregion
              }
          }
      }
      
    • 使用Cors Nuget包并注册服务

      中间件支持跨域,依赖于程序包:Microsoft.AspNetCore.Cors

services.AddCors(option => option.AddPolicy("AllowCors", build =>build.AllowAnyOrigin().AllowAnyMethod()));
app.UseCors("AllowCors"); //必须要在UseRouting之后 在UseAuthorization之前。
  public void ConfigureServices(IServiceCollection services)
        {
             services.AddCors(option => option.AddPolicy("AllowCors", _build => _build.AllowAnyOrigin().AllowAnyMethod()));
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
       {
             //使用中间件
             app.UseRouting();
             app.UseCors("AllowCors");
             #region 通过中间件来支持鉴权授权
             app.UseAuthentication();
             #endregion             
             app.UseAuthorization();
       }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

袁鹤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值