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

posted @ 2020-11-30 14:01  寻找现实的感觉  阅读(656)  评论(0)    收藏  举报