.Net WebAPI JWT身份驗證
阿新 • • 發佈:2018-12-19
一、開發環境
VS2017 enterprise
win10 Pro 64
.net 4.6.2
二、開發過程
1、使用VS2017 建立.netframework專案,選擇WebApi
2、從Nuget包中搜索並安裝JWT
3、在Models中建立AuthInfo.cs、LoginRequest.cs、TokenInfo.cs三個類
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace apiToken.Models { /// <summary> /// 身份驗證資訊 模擬JWT的payload /// </summary> public class AuthInfo { /// <summary> /// 使用者名稱 /// </summary> public string UserName { get; set; } /// <summary> /// 角色 /// </summary> public List<string> Roles { get; set; } /// <summary> /// 是否管理員 /// </summary> public bool IsAdmin { get; set; } /// <summary> /// 口令過期時間 /// </summary> public DateTime? ExpiryDateTime { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace apiToken.Models { /// <summary> /// 登入使用者資訊 /// </summary> public class LoginRequest { /// <summary> /// 使用者名稱 /// </summary> public string UserName { get; set; } /// <summary> /// 密碼 /// </summary> public string Password { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace apiToken.Models { /// <summary> /// 生成的口令資訊 /// </summary> public class TokenInfo { /// <summary> /// 是否成功 /// </summary> public bool Success { get; set; } /// <summary> /// 令牌 /// </summary> public string Token { get; set; } /// <summary> /// 錯誤資訊 /// </summary> public string Message { get; set; } } }
4、在Controllers資料夾下建立TokenController.cs檔案,生成口令
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using apiToken.Models;
using System.Text;
namespace apiToken.Controllers
{
[RoutePrefix("api/Token")]
public class TokenController : ApiController
{
/// <summary>
/// 登入
/// </summary>
/// <param name="loginRequest"></param>
/// <returns></returns>
[HttpPost]
[Route("Login")]
public TokenInfo Login([FromBody] LoginRequest loginRequest)
{
TokenInfo tokenInfo = new TokenInfo();//需要返回的口令資訊
if (loginRequest != null)
{
string userName = loginRequest.UserName;
string passWord = loginRequest.Password;
bool isAdmin = (userName == "admin")?true:false;
//模擬資料庫資料,真正的資料應該從資料庫讀取
//身份驗證資訊
AuthInfo authInfo = new AuthInfo { UserName=userName,Roles=new List<string> {"admin","commonrole"}, IsAdmin= isAdmin, ExpiryDateTime=DateTime.Now.AddHours(2)};
const string secretKey = "Hello World";//口令加密祕鑰
try
{
byte[] key = Encoding.UTF8.GetBytes(secretKey);
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//加密方式
IJsonSerializer serializer = new JsonNetSerializer();//序列化Json
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//base64加解密
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);//JWT編碼
var token = encoder.Encode(authInfo, key);//生成令牌
//口令資訊
tokenInfo.Success = true;
tokenInfo.Token = token;
tokenInfo.Message = "OK";
}
catch(Exception ex)
{
tokenInfo.Success = false;
tokenInfo.Message = ex.Message.ToString();
}
}
else
{
tokenInfo.Success = false;
tokenInfo.Message = "使用者資訊為空";
}
return tokenInfo;
}
}
}
5、在專案中新增AuthAttributes資料夾,並且在資料夾在建立ApiAuthorizeAttribute.cs檔案,用於建立身份攔截器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using JWT;
using JWT.Serializers;
using apiToken.Models;
using System.Text;
using System.Net;
using System.Net.Http;
namespace apiToken.AuthAttributes
{
/// <summary>
/// 身份認證攔截器
/// </summary>
public class ApiAuthorizeAttribute: AuthorizeAttribute
{
/// <summary>
/// 指示指定的控制元件是否已獲得授權
/// </summary>
/// <param name="actionContext"></param>
/// <returns></returns>
protected override bool IsAuthorized(HttpActionContext actionContext)
{
//前端請求api時會將token存放在名為"auth"的請求頭中
var authHeader = from t in actionContext.Request.Headers where t.Key == "auth" select t.Value.FirstOrDefault();
if (authHeader != null)
{
const string secretKey = "Hello World";//加密祕鑰
string token = authHeader.FirstOrDefault();//獲取token
if (!string.IsNullOrEmpty(token))
{
try
{
byte[] key = Encoding.UTF8.GetBytes(secretKey);
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, key, verify: true);
if (json != null)
{
//判斷口令過期時間
if (json.ExpiryDateTime < DateTime.Now)
{
return false;
}
actionContext.RequestContext.RouteData.Values.Add("auth", json);
return true;
}
return false;
}
catch (Exception ex)
{
return false;
}
}
}
return false;
}
/// <summary>
/// 處理授權失敗的請求
/// </summary>
/// <param name="actionContext"></param>
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
var erModel = new
{
Success="false",
ErrorCode="401"
};
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, erModel, "application/json");
}
/// <summary>
/// 為操作授權時呼叫
/// </summary>
/// <param name="actionContext"></param>
//public override void OnAuthorization(HttpActionContext actionContext)
//{
//}
}
}
6、建立UserInfoController.cs 用於測試身份驗證
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using apiToken.AuthAttributes;
using Newtonsoft.Json;
namespace apiToken.Controllers
{
[RoutePrefix("api/UserInfo")]
[ApiAuthorize]
public class UserInfoController : ApiController
{
/// <summary>
/// 獲取使用者資訊
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("GetUserInfo")]
public string GetUserInfo()
{
var userInfo = new
{
UserName="test",
Tel="123456789",
Address="testddd"
};
return JsonConvert.SerializeObject(userInfo);
}
}
}
最後將webapi介面在IIS中釋出,通過PostMan進行測試
如果Token不正確或者Token失效則不會進入請求
注:如果遇到跨域的問題,可以下webconfig中做如下配置