• web api 之jwt认证


    1. 什么是JWT

    Json web Token是一个开放的标准,这个标准允许我们使用jwt在用户和服务器之间传递安全可靠的信息。

    1. jwt的组成

    结构:头部(Header)、载荷(payload)、签名(signature)

    1.头部(Header)

    {

      "typ": "JWT",

      "alg": "HS256"

    }

    这里声明类型和加密算法,要进行Base64编码得到的编码是jwt的Header

    2.载荷(payload)

    {

        "iss": "John Wu JWT",

        "iat": 1441593502,

        "exp": 1441594722,

        "aud": "www.example.com",

        "sub": "jrocket@example.com",

    }

    这里面的前五个字段都是由JWT的标准所定义的。

    • iss: 该JWT的签发者
    • sub: 该JWT所面向的用户
    • aud: 接收该JWT的一方
    • exp(expires): 什么时候过期,这里是一个Unix时间戳
    • iat(issued at): 在什么时候签发的

    将该json对象进行base64编码得到的字符串就是jwt的Payload(载荷)

    1. 签名(signature)

    将Header和Payload编码后的字符串都用句号.连在一起(头部在前面)得到的字符串,用

    HS256算法进行加密。加密的时候提供一个密钥(secret).

    这一部分又叫做签名。

      最后将这一部分签名也拼接在被签名的字符串后面,我们就得到完整的jwt.

    3.jwt适用的场景

    加好友的操作、下订单的操作、设计用户认证和授权系统、web应用的单点登录

    1. web api使用jwt认证

    1.建立一个web api项目

    2.项目右键-管理Nuget程序包—找到jwt,安装

    3.Model文件夹下新建三个类LoginResult,LoginRequest,AuthInfo

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

     

    namespace WebApplication13.Models

    {

        public class LoginResult

        {

     

            public bool Success { get; set; }

     

             public string Token { get; set; }

     

             public string Message { get; set; }

        }

    }

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

     

    namespace WebApplication13.Models

    {

        public class LoginRequest

        {

     

            public string UserName { get; set; }

     

             public string Password { get; set; }

        }

    }

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

     

    namespace WebApplication13.Models

    {

        public class AuthInfo

        {

     

              //模拟JWT的payload

             public string UserName { get; set; }

     

             public List<string> Roles { get; set; }

     

             public bool IsAdmin { get; set; }

        }

    }

    4.在controller文件夹中的HomeController中添加一个Post方法,这是生成JWT Token方法的地方。

    using JWT;

    using JWT.Algorithms;

    using JWT.Serializers;

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Net;

    using System.Net.Http;

    using System.Web.Http;

    using System.Web.Http.Cors;

    using WebApplication13.Models;

     

    namespace WebApplication13.Controllers

    {

        [EnableCors(origins: "http://localhost:62815", headers: "*", methods: "GET,POST,PUT,DELETE")]

        public class HomeController : ApiController

        {

            public LoginResult Post([FromBody]LoginRequest request)

            {

                LoginResult rs = new LoginResult();

                //这是是获取用户名和密码的,这里只是为了模拟

                if (request.UserName == "kfz" && request.Password == "123456")

                {

                    AuthInfo info = new AuthInfo { UserName = "kfz", Roles = new List<string> { "Admin", "Manage" }, IsAdmin = true };

                    try

                    {

                        const string secret = "To Live is to change the world";

                        //secret需要加密

                        IJwtAlgorithm algorithm = new HMACSHA256Algorithm();

                        IJsonSerializer serializer = new JsonNetSerializer();

                        IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();

                        IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);

                        var token = encoder.Encode(info, secret);

                        rs.Message = "XXXXX";

                        rs.Token = token;

                        rs.Success = true;

                    }

                    catch (Exception ex)

                    {

                        rs.Message = ex.Message;

                        rs.Success = false;

                    }

                }

                else

                {

                    rs.Message = "fail";

                    rs.Success = false;

                }

                return rs;

            }

        }

    }

    1. 项目中添加一个Attributes文件夹,写一个权限拦截器,新建一个ApiAuthorizeAttribute类继承自AuthorizeAttribute类

      using JWT;

    using JWT.Serializers;

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.Web.Http;

    using System.Web.Http.Controllers;

    using WebApplication13.Models;

    namespace WebApplication13.Attributes

    {

        public class ApiAuthorizeAttribute: AuthorizeAttribute

        {

            protected override bool IsAuthorized(HttpActionContext actionContext)

            {

                var authHeader = from t in actionContext.Request.Headers where t.Key == "auth" select t.Value.FirstOrDefault();

                 if (authHeader != null)

                 {

                     string token = authHeader.FirstOrDefault();

                     if (!string.IsNullOrEmpty(token))

                     {

                         try

                         {

                             const string secret = "To Live is to change the world";

                             //secret需要加密

                             IJsonSerializer serializer = new JsonNetSerializer();

                             IDateTimeProvider provider = new UtcDateTimeProvider();

                             IJwtValidator validator = new JwtValidator(serializer, provider);

                             IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();

                             IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);

                             var json = decoder.DecodeToObject<AuthInfo>(token, secret, verify: true);

                             if (json != null)

                             {

                                 actionContext.RequestContext.RouteData.Values.Add("auth", json);

                                 return true;

                             }

                             return false;

                         }

                         catch (Exception ex)

                         {

                             return false;

                         }

                     }

                 }

                 return false;

             }

         }

     }

    1. controller文件夹中新建一个UserController,新建一个Get的Action,需要加上ApiAuthorize特性

       using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Net;

    using System.Net.Http;

    using System.Web.Http;

    using System.Web.Http.Cors;

    using WebApplication13.Attributes;

    using WebApplication13.Models;

     

    namespace WebApplication13.Controllers

    {

        [EnableCors(origins: "http://localhost:62815", headers: "*", methods: "GET,POST,PUT,DELETE")]

        public class UserController : ApiController

        {

     

            // GET: User

            [ApiAuthorize]

            public string Get()

            {

                AuthInfo info = RequestContext.RouteData.Values["auth"] as AuthInfo;

                if (info == null)

                {

                    return "获取不到,失败";

                }

                else

                {

                    return $"获取到了,Auth的Name是 {info.UserName}";

                }

            }

        }

    }

    1. 对于跨域问题可以参考之前的web api的文章,这里我使用的是特性

      [EnableCors(origins: "http://localhost:62815", headers: "*", methods: "GET,POST,PUT,DELETE")]

     

     

    1. 部署web api到服务器上,然后用另一个跨域的页面调用接口访问

     

    @{

        ViewBag.Title = "Test";

    }

     

    <!DOCTYPE html>

    <html>

    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

        <title></title>

        <meta charset="utf-8" />

        <script src="~/Scripts/jquery-3.3.1.min.js"></script>

    </head>

    <body>

        <fieldset>

            <legend>身份验证</legend>

            <form>

                <label for="UserName">用户名:</label><input type="text" name="userName" id="userName" value="admin" />

                <br />

                <br />

                <label for="Password">密码:</label><input type="password" name="password" id="password" value="123" />

                <br />

                <br />

            </form>

            <button id="login">登录</button>

        </fieldset>

        <br />

     

        <fieldset>

            <legend>调用接口</legend>

            <button id="invoke">调用接口</button>

        </fieldset>

        <script>

            $(function () {

                //调用api站点的登录接口,接口在登录成功后返回一个token。

                $("#login").on("click", function () {

                    $.ajax({

                        url: "http://localhost:55221/api/home",

                        data: $("form").serialize(),

                        method: "post",

                        success: function (data) {

                            if (data.Success) {

                                //为简单起见,将token保存在全局变量中。

                                window.token = data.Token;

                                alert("登录成功");

                            } else {

                                alert("登录失败:" + data.Message);

                            }

                        }

                    });

                });

     

                //调用api站点的获取数据的接口,该接口要求身份验证。

                $("#invoke").on("click", function () {

                    console.log(window.token);

                    $.ajax({

                        url: "http://localhost:55221/api/user",

                        method: "get",

                        headers: { "auth": window.token },//通过请求头来发送token,放弃了通过cookie的发送方式

                        complete: function (jqXHR,textStatus) {

                            alert(jqXHR.responseText);

                        },

     

                    });

                });

            });

        </script>

    </body>

    </html>

     

    本文参考链接:

    https://www.cnblogs.com/lwhkdash/p/6686999.html

    https://www.cnblogs.com/wangyulong/p/8727683.html

  • 相关阅读:
    stm32f103和stm32f407的GPIO口模式设置以及相互对应的关系
    基于STM32单片机实现屏幕休眠后OLED屏幕滚动效果
    基于51单片机的超声波模块HC-SR04的使用
    用51单片机控制L298N电机驱动模块
    学习笔记——51单片机 单片机与单片机之间的通讯
    基于51单片机的电子密码锁—1
    LCD1602学习调试
    基于51单片机,通过定时器实现的时钟程序
    有进度条圆周率计算
    python turtle 学习笔记
  • 原文地址:https://www.cnblogs.com/Vinkong/p/14060958.html
Copyright © 2020-2023  润新知