首页 > 技术文章 > .Net 5框架下的Web API+JWT or Identtityservice4

LZXX 2021-05-06 17:13 原文

目录

1.Rest_Full风格
2. wep api Swageer 
3.cmd命令程序开启web程序 
4.api 前后端调用例子
5.浏览器跨域,同源策略
6.请求压缩响应结果
7.鉴权中心
8. JWT验证流程思路

 

1.Rest_Full风格:不再是调用方法,把服务资源化(所有东西视为资源)看做一个整体,对外提供URL-统一资源定位器 提供Get/Post/Delete/Update

2..Net5 默认自带Swageer 注意,statup中间件注册没生效可能会存在顺序关系!

3.cmd命令程序开启web程序

再vs里面右键项目程序-打开程序所在的文件夹 在当前目录输入cmd进入命令程序

输入命令 dotnet  run --urls=“http://*:5400” 

 

 

4.api 前后端调用例子

namespace Zhaoxi.AspNetCoreDemo.WebApi.Controllers
{
    /// <summary>
    /// 特性路由
    /// template:中括号代表 变量
    /// 控制器上标的Route模板和Action上标记Route模板内容会链接起来
    /// 如果加上特性路由以后:确定到方法了,以路由定义的名称为准
    /// </summary>
    //[Route("api/[controller]")]
    //[CustomActionFilterAttribute]//整个控制器都支持跨域了;
    [ApiExplorerSettings(GroupName = "V1")]
    [ApiController] //WebApi特有
    public class FirstController : ControllerBase
    {

        [HttpGet]
        [Route("api/[controller]/GetDataTable")]
        public DataTable GetDataTable()
        {
            return null;
        }


        /// <summary>
        /// 这是V1版本的GetString
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("api/[controller]/GetString")]
        public string GetToString()
        {

            //HttpContext.Response.Headers.Add("Access-Control-Allow-Origin","*");//允许跨域了;
            var reuslt = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                Id = 123,
                Name = "闪电五连鞭"
            });

            Console.WriteLine(reuslt);

            return reuslt;
        }

        /// <summary>
        /// 这是V1版本的GetString002
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("api/[controller]/GetString002")]
        public string GetString002()
        {
            //HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");//允许跨域了;
            return Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                Id = 123,
                Name = "闪电五连鞭"
            });
        }

        /// <summary>
        /// 这是V1版本的Add
        /// </summary>
        /// <returns>name</returns>
        [HttpPost]
        [Route("api/[controller]/Add/{name:required}")]
        public string Add(string name)
        {
            //HttpContext.Response.Headers.Add("Access-Control-Allow-Origin","*");//允许跨域了;
            return Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                Id = 234,
                Name = name
            });
        }

        [HttpPut]
        [Route("api/[controller]/Update/{id:int}")]
        public int Update(int Id)
        {
            return Id;
        }
        [Route("api/[controller]/Update/{id:int}")]
        [HttpDelete]
        public int Delete(int Id)
        {
            return Id;
        }

        [Route("api/[controller]/Patch")]
        [HttpPatch]
        public int Patch()
        {
            return 123;
        }

        [Route("api/[controller]/GetUser")]
        [HttpPost]
        public string GetUser(Users user)
        {
            Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(user));
            return Newtonsoft.Json.JsonConvert.SerializeObject(user);
        }


        [Route("api/[controller]/GetStudent")]
        [HttpGet]
        public string GetStudent()
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                id = 234,
                Name = "笑脸",
                Age = 24,
                Description = "奥术大师多"
            });
        }
    }
}
后端接收
@{
    ViewData["Title"] = "Index";
}

<h1>this is  Client Api</h1>

<form method="post" action="/api/Ninth/register?id=1">
    <div class="row">
        <div class="col-md-5">
            <h2>Test </h2>
            <p>
                <input type="text" id="txtAccount" name="账号" />
                <input type="text" id="txtPassword" name="密码" />
                <input type="button" id="btnLogin" value="登陆" />
            </p>

            <p><input type="text" id="txtId" name="id" /> </p>
            <p>
                <input type="button" id="btnGet1" value="Get1" />
                <input type="button" id="btnGet2" value="Get2" />
                <input type="button" id="btnGet3" value="Get3" />
                <input type="button" id="btnGet4" value="Get4" />
            </p>
            <p>
                <input type="button" id="btnGet5" value="Get5" />
                <input type="button" id="btnGet6" value="Get6" />
                <input type="button" id="btnGet7" value="Get7" />
            </p>

            <p>
                <input type="button" id="btnPost1" value="Post1" />
                <input type="button" id="btnPost2" value="Post2" />
                <input type="button" id="btnPost3" value="Post3" />
                <input type="button" id="btnPost4" value="Post4" />
            </p>
            @*<p><input type="submit" id="btnPost" /> </p>*@
            <p>
                <input type="button" id="btnPut1" value="Put1" />
                <input type="button" id="btnPut2" value="Put2" />
                <input type="button" id="btnPut3" value="Put3" />
                <input type="button" id="btnPut4" value="Put4" />
                @*<input type="button" id="btnPut5" value="Put5" />
            <input type="button" id="btnPut6" value="Put6" />*@
            </p>
            <p>
                <input type="button" id="httpGet" value="后台模拟HttpGet请求" />
                <input type="button" id="httpPost" value="后台模拟HttpPost请求" />
            </p>
            <p>
                <input type="button" id="btnGetCors1" value="跨域Get1" />
            </p>
        </div>

    </div>
    <script src="~/lib/jquery/dist/jquery.min.js"></script> 
    <script>
        $(function () {
            var user = { UserID: "11", UserName: "Richard", UserEmail: "1030499676@qq.com" };
            var info = "this is muti model";

            $("#btnGet1").on("click", function () {
                //$.ajax({ url: "/api/Ninth", type: "get", data: { "userName": "Superman" }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });//指向接口,参数匹配的,大小写不区分
                $.ajax({
                    //url: "/api/Ninth/GetUserByName?ticket=" + ticket
                    url: "/api/Ninth/GetUserByName", type: "get", data: { "username": "Superman" },
                    //beforeSend: function (XHR) {
                    //    //发送ajax请求之前向http的head里面加入验证信息
                    //    XHR.setRequestHeader('Authorization', 'BasicAuth ' + ticket);
                    //},
                    success: function (data) {
                        alert(JSON.stringify(data));
                    }, datatype: "json"
                });
            });
            $("#btnGet2").on("click", function () {//单个参数
                $.ajax({ url: "/api/Ninth/GetUserByID", type: "get", data: { "id": $("#txtId").val() }, success: function (data) { alert(JSON.stringify(data)); }, datatype: "json" });
            });
            $("#btnGet3").on("click", function () {//两个参数
                $.ajax({ url: "/api/Ninth/GetUserByNameId", type: "get", data: { "userName": "Superman", "id": $("#txtId").val() }, success: function (data) { alert(JSON.stringify(data)); }, datatype: "json" });
            });
            $("#btnGet4").on("click", function () {//无参数
                $.ajax({ url: "/api/Ninth/Get", type: "get", data: "", success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });
            $("#btnGet5").on("click", function () {//传递实体,序列化后传递
                $.ajax({ url: "/api/Ninth/GetUserByModelSerialize", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });

            //只能传递JSON字符串、[frombody] [fromuri] [fromform]---现在不行
            $("#btnGet6").on("click", function () {//传递实体,序列化后传递
                $.ajax({ url: "/api/Ninth/GetUserByModelSerializeWithoutGet", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });
            $("#btnGet7").on("click", function () {//传递实体,序列化后传递  405 Method Not Allowed    不带httpget需要用get开头
                $.ajax({ url: "/api/Ninth/NoGetUserByModelSerializeWithoutGet", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });


            $("#btnPost1").on("click", function () {//单个值传递,json数据不要key,这样后台才能获取
                $.ajax({ url: "/api/Ninth/RegisterNone", type: "post", data: {}, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });
            $("#btnPost2").on("click", function () {//key-value形式后台拿不到这个参数,但是可以直接访问
                $.ajax({ url: "/api/Ninth/Register", type: "post", data: { "id": $("#txtId").val() }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });
            $("#btnPost3").on("click", function () {//传递json格式的,后台可以用实体接收
                $.ajax({ url: "/api/Ninth/RegisterUser", type: "post", data: user, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });
            $("#btnPost4").on("click", function () {//传递json序列化后的格式
                $.ajax({ url: "/api/Ninth/RegisterUser", type: "post", data: JSON.stringify(user), success: function (data) { alert(JSON.stringify(data));  }, datatype: "json", contentType: 'application/json', });
            });

            //也可以还是包装成一个对象

            $("#btnPut1").on("click", function () {//单个值传递,json数据不要key,这样后台才能获取
                $.ajax({ url: "/api/Ninth/RegisterNoKeyPut", type: "put", data: { "": $("#txtId").val() }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });
            $("#btnPut2").on("click", function () {//key-value形式后台拿不到
                $.ajax({ url: "/api/Ninth/RegisterPut", type: "put", data: { "id": $("#txtId").val() }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });
            $("#btnPut3").on("click", function () {//传递json格式的,后台可以用实体接收
                $.ajax({ url: "/api/Ninth/RegisterUserPut", type: "put", data: user, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });
            $("#btnPut4").on("click", function () {//传递json序列化后的格式,后台可以用实体接收,需要指定contentType
                $.ajax({ url: "/api/Ninth/RegisterUserPut", type: "put", data: JSON.stringify(user), success: function (data) { alert(JSON.stringify(data));  }, datatype: "json", contentType: 'application/json', });
            });

            $("#httpGet").on("click", function () { //先请求到后台,然后由后台发送HttpGet请求再请求到第三方WebApi
                $.ajax({ url: "SendHttpGet", type: "get", data: {}, success: function (data) { alert(JSON.stringify(data)); }, datatype: "json", contentType: 'application/json', });
            });

            $("#httpPost").on("click", function () { //先请求到后台,然后由后台发送HttpPost请求再请求到第三方WebApi
                $.ajax({ url: "SendHttpPost", type: "post", data: {}, success: function (data) { alert(JSON.stringify(data)); }, datatype: "json", contentType: 'application/json', });
            });

            //$("#btnPut5").on("click", function () {//JObject接收
            //    $.ajax({ url: "/api/Ninth/RegisterObjectPut", type: "put", data: { "User": user, "Info": info }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            //});
            //$("#btnPut6").on("click", function () {//Dynamic  失败了
            //    $.ajax({ url: "/api/Ninth/RegisterObjectDynamicPut", type: "put", data: { "User": user, "Info": info }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json", contentType: 'application/json' });
            //});

            //delete一样 type换成delete
            //如果大家还有别的传递和获取 自动绑定好的方式,欢迎分享

            $("#btnLogin").on("click", function () {
                $.ajax({
                    url: "/api/Ninth/Login",
                    type: "GET",
                    data: { "Account": $("#txtAccount").val(), "Password": $("#txtPassword").val() },
                    success: function (data) {
                        var result = JSON.parse(data);
                        if (result.Result) {
                            ticket = result.Ticket;
                            alert(result.Ticket);
                        }
                        else {
                            alert("failed");
                        }
                    }, datatype: "json"
                });
            });

            var ticket = "";//登陆后放在某个html里面,ajax都得带上

            jQuery.support.cors = true;
            var location = "https://localhost:5400/api/first/GetString";
            $("#btnGetCors1").on("click", function () {
                $.ajax({ url: location, type: "get", data: { "id": 1 }, success: function (data) { alert(JSON.stringify(data));  }, datatype: "json" });
            });

        });
    </script>
</form>
前端调用

 5.浏览器跨域,同源策略

正常:正常http请求是通过浏览器发送给服务器 服务器知道请求人的http协议的信息,如:端口,ip

跨域:ajax http请求是直接一个链接请求到服务器,服务器不知道请求人的身份。

如果没有同源策略.存储在服务器的cookie session 谁过来都能读取

 

 

 经典的跨域请求错误事例:

 多种跨域策略之一 

服务器设置全局允许跨域请求 statup.cs.configure():或者使用特性,控制某个控制器允许跨域

多种跨域策略之一 在statup.cs.ConfigureServices()下面

 

 多种跨域策略之二, 在statup.cs.Configure()下面

app.UseCors("AllowCors"); //必须要在UseRouting 之后 在 UseAuthorization之前

 

6.请求压缩响应结果

添加程序集:

 

 在statup.cs下添加代码  支持GZip压缩格式,或者同事支持两种

在statup.cs.Configure()下面

 

浏览器支持的压缩方式

 

 

 7.鉴权中心

 

 Token检验流程

 

 8. JWT验证流程思路

1.用户访问鉴权中心,鉴权返回用户token 
2.用户带着token 访问api  api得到用于的token 并不去AuthorizetionServer鉴权中心去访问 

验证流程
api要确定的是这个token是否来自于鉴权中心的token?
如果是来自于鉴权中心的token,如何判断token是否失效?

这时候就需要用到加密技术
1. Des 对称可逆加密
2. Rsa 非对称可逆加密
对称可逆加密: 就是一个key,key可以加密,也必须使用这个key才能够解密
鉴权中心:key1
Api方法:key1    鉴权中心和api是同一个key;
token验证流程:
1.用户在鉴权中心登录成功以后,可以使用key1加密;得到一段密文;
2.用户访问Api的时候,Api方就使用ke1去解密:
4.如果解密成功---防止抵赖(密文一定是来自于鉴权中心),
5.就进一步验证token是否过期,
6.如果过期就拦截,如果没有过期就通过

实际开发中:内网对称可逆加密,性能更优 外网:非对称可逆加密,更安全
JWT:  一对key,   二者无法相互推导; 私钥、公钥;
私钥-----鉴权中心;作为加密Key
公钥-----Api方法;作为解密key; 
Api方法只要是通过公钥能够解开密文;说明token是来自于鉴权中心

JWT验证流程
1.新增 JWT鉴权中心程序,配置相关逻辑(jwt一般是给的独立的程序和服务器)
2.http第一次登陆到鉴权中心,JWT通过用户名密码,使用非对称加密生成公钥和私钥保存在本地磁盘, 使用私钥生成加密key 把公钥文件给客户端 3.客户度拿到token令牌去访问Api的时候, api通过jwt给的公钥文件解密,解密成功就证明是jwt给的token,不成功则不是jwt给的toeken,之后得到相关信息

  

 9.AJAX 携带token验证

前端代码如下

程序已经在中间件支持了跨域,但是会报错

1.还是会出现跨域报错

需要在statup.cs增加如下代码 

2.并且还会请求两次

 

 第一次请求报错,第二次请求 返回:204

 解决如下:在statup.cs中间件里面增加如下代码,页面清楚缓存

 

10. identityservice4.0

1.如果鉴权中间是第三方,1.那么可能造成密码泄露  比如A 去请求第三方鉴权中心b  2.回收权限不方便

2.accesstoken,通行证

 

推荐阅读