Fork me on GitHub

WebApi使用JWT认证(一)

这是第一部:先实现NetFramework上的WebApi使用JWT认证

1、VS新建一个WebApi项目

2、项目右键----管理Nuget程序包----找到JWT,然后安装

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

 1 namespace JwtWebApi.Models
 2 {
 3     public class LoginResult
 4     {
 5         public bool Success { get; set; }
 6 
 7         public string Token { get; set; }
 8 
 9         public string Message { get; set; }
10     }
11 }
1 namespace JwtWebApi.Models
2 {
3     public class LoginRequest
4     {
5         public string UserName { get; set; }
6 
7         public string Password { get; set; }
8     }
9 }
 1 using System.Collections.Generic;
 2 
 3 namespace JwtWebApi.Models
 4 {
 5     public class AuthInfo
 6     {
 7         //模拟JWT的payload
 8         public string UserName { get; set; }
 9 
10         public List<string> Roles { get; set; }
11 
12         public bool IsAdmin { get; set; }
13     }
14 }

4、在Controllers文件夹中的HomeController(没有就新建一个)中添加一个Post方法,这是生成JWT Token方法的地方,一般应放在登录的Action下

 1 using JWT;
 2 using JWT.Algorithms;
 3 using JWT.Serializers;
 4 using JwtWebApi.Models;
 5 using System;
 6 using System.Collections.Generic;
 7 using System.Web.Http;
 8 
 9 namespace JwtWebApi.Controllers
10 {
11     public class HomeController : ApiController
12     {
13         public LoginResult Post([FromBody]LoginRequest request)
14         {
15             LoginResult rs = new LoginResult();
16             //这是是获取用户名和密码的,这里只是为了模拟
17             if (request.UserName == "wangshibang" && request.Password == "123456")
18             {
19                 AuthInfo info = new AuthInfo { UserName = "wangshibang", Roles = new List<string> { "Admin", "Manage" }, IsAdmin = true };
20                 try
21                 {
22                     const string secret = "To Live is to change the world";
23                     //secret需要加密
24                     IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
25                     IJsonSerializer serializer = new JsonNetSerializer();
26                     IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
27                     IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
28                     var token = encoder.Encode(info, secret);
29                     rs.Message = "XXXXX";
30                     rs.Token = token;
31                     rs.Success = true;
32                 }
33                 catch (Exception ex)
34                 {
35                     rs.Message = ex.Message;
36                     rs.Success = false;
37                 }
38             }
39             else
40             {
41                 rs.Message = "fail";
42                 rs.Success = false;
43             }
44             return rs;
45         }
46     }
47 }

5、项目下添加一个Attributes文件夹,需要写个权限拦截器,新建一个ApiAuthorizeAttribute类继承自AuthorizeAttribute类

 1 using JWT;
 2 using JWT.Serializers;
 3 using JwtWebApi.Models;
 4 using System;
 5 using System.Linq;
 6 using System.Web.Http;
 7 using System.Web.Http.Controllers;
 8 
 9 namespace JwtWebApi.Attributes
10 {
11     public class ApiAuthorizeAttribute : AuthorizeAttribute
12     {
13         protected override bool IsAuthorized(HttpActionContext actionContext)
14         {
15             var authHeader = from t in actionContext.Request.Headers where t.Key == "auth" select t.Value.FirstOrDefault();
16             if (authHeader != null)
17             {
18                 string token = authHeader.FirstOrDefault();
19                 if (!string.IsNullOrEmpty(token))
20                 {
21                     try
22                     {
23                         const string secret = "To Live is to change the world";
24                         //secret需要加密
25                         IJsonSerializer serializer = new JsonNetSerializer();
26                         IDateTimeProvider provider = new UtcDateTimeProvider();
27                         IJwtValidator validator = new JwtValidator(serializer, provider);
28                         IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
29                         IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);
30 
31                         var json = decoder.DecodeToObject<AuthInfo>(token, secret, verify: true);
32                         if (json != null)
33                         {
34                             actionContext.RequestContext.RouteData.Values.Add("auth", json);
35                             return true;
36                         }
37                         return false;
38                     }
39                     catch (Exception ex)
40                     {
41                         return false;
42                     }
43                 }
44             }
45             return false;
46         }
47     }
48 }

6、Controllers文件夹中新建一个UserController,新建一个Get的Action,需要加上ApiAuthorize特性

 1 using JwtWebApi.Attributes;
 2 using JwtWebApi.Models;
 3 using System.Web.Http;
 4 
 5 namespace JwtWebApi.Controllers
 6 {
 7     public class UserController : ApiController
 8     {
 9         // GET: User
10         [ApiAuthorize]
11         public string Get()
12         {
13             AuthInfo info = RequestContext.RouteData.Values["auth"] as AuthInfo;
14             if (info == null)
15             {
16                 return "获取不到,失败";
17             }
18             else
19             {
20                 return $"获取到了,Auth的Name是 {info.UserName}";
21             }
22         }
23     }
24 }

7、然后用PostMan测试

下面是解决接口调用的跨域问题,有两种,一种是用CORS,另外一种就是修改WebConfig添加自定义options谓词处理模块

我只用了自定义Options谓词处理

 1 <system.webServer>
 2     <handlers>
 3       <!--开启options谓词处理模块-->
 4       <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
 5       <!--<remove name="OPTIONSVerbHandler" />-->
 6       <remove name="TRACEVerbHandler" />
 7       <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
 8     </handlers>
 9     <httpProtocol>
10       <customHeaders>
11         <!--添加自定义options谓词处理模块-->
12         <add name="Access-Control-Allow-Origin" value="http://localhost:8057"/>
13         <add name="Access-Control-Allow-Headers" value="accept, auth"/>
14         <add name="Access-Control-Allow-Methods" value="GET, OPTIONS"/>
15       </customHeaders>
16     </httpProtocol>
17     <validation validateIntegratedModeConfiguration="false" />
18     <modules>
19       <remove name="ApplicationInsightsWebTracking" />
20       <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
21     </modules>
22   </system.webServer>

好了,现在把你的WebApi部署到服务器上,然后用另一个跨域页面调取接口访问吧

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 5     <title></title>
 6     <meta charset="utf-8" />
 7     <script src="jquery-3.3.1.min.js"></script>
 8 </head>
 9 <body>
10     <fieldset>
11         <legend>身份验证</legend>
12         <form>
13             <label for="UserName">用户名:</label><input type="text" name="userName" id="userName" value="admin" />
14             <br />
15             <br />
16             <label for="Password">密码:</label><input type="password" name="password" id="password" value="123" />
17             <br />
18             <br />
19         </form>
20         <button id="login">登录</button>
21     </fieldset>
22     <br />
23 
24     <fieldset>
25         <legend>调用接口</legend>
26         <button id="invoke">调用接口</button>
27     </fieldset>
28     <script>
29         $(function () {
30             //调用api站点的登录接口,接口在登录成功后返回一个token。
31             $("#login").on("click", function () {
32                 $.ajax({
33                     url: "http://localhost:8056/api/home",
34                     data: $("form").serialize(),
35                     method: "post",
36                     success: function (data) {
37                         if (data.Success) {
38                             //为简单起见,将token保存在全局变量中。
39                             window.token = data.Token;
40                             alert("登录成功");
41                         } else {
42                             alert("登录失败:" + data.Message);
43                         }
44                     }
45                 });
46             });
47 
48             //调用api站点的获取数据的接口,该接口要求身份验证。
49             $("#invoke").on("click", function () {
50                 console.log(window.token);
51                 $.ajax({
52                     url: "http://localhost:8056/api/user",
53                     method: "get",
54                     headers: { "auth": window.token },//通过请求头来发送token,放弃了通过cookie的发送方式
55                     complete: function (jqXHR,textStatus) {
56                         alert(jqXHR.responseText);
57                     },
58                     
59                 });
60             });
61         });
62     </script>
63 </body>
64 </html>

本文参考链接:https://www.cnblogs.com/lwhkdash/p/6686999.html

posted @ 2018-04-06 14:30  雪山玉龙  阅读(...)  评论(...编辑  收藏