基于.Net Framework 4.0 Web API开发(4):ASP.NET Web APIs 基于令牌TOKEN

时间:2021-10-29 20:08:48

标签:

概述: 

  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作。但是在使用API的时候总会遇到跨域请求的问题, 特别各种APP万花齐放的今天,对API使用者身份角色验证是不能避免的(完全开发的API不需要对使用者身份角色进行管控,可以绕过),这篇文章就来谈谈基于令牌TOKEN身份验证的实现。

问题:

   对于Web API的选择性的开放,使用者无论使用AJAX,,还是HttpClient对接,总要对使用者的身份角色进行验证,然而使用API总有跨域使用情况的存在,这样就导致所有基于cookie验证方式都不再适用于API的验证。

原因:

  比如,基于form表单验证的基础是登录验证成功后,用户的信息存在缓存或数据库或cookie,无论哪种方式存储用户信息,都不能绕过对cookie的使用,所以form表单验证方法对于禁用cookie的浏览器都不能正常使用,结论就是不能使用cookie 的环境就不能使用基本的form表单验证方式。因此WEB API 由于跨域的使用,导致cookie不能正常工作,所以不能再使用基于表单验证的方式来实现。

基于令牌TOKEN验证方法的实现:

方法一:

1. 实现对缓存TOKEN的管理,以防IIS服务器的宕机,可以对TOKEN进行持久化存储处理,每次IIS重启重新初始化已经登录成功TOKEN缓存。实现如下:

1 public class UserTokenManager 2 { 3 private static readonly IUserTokenRepository _tokenRep; 4 private const string TOKENNAME = "PASSPORT.TOKEN"; 5 6 static UserTokenManager() 7 { 8 _tokenRep = ContainerManager.Resolve<IUserTokenRepository>(); 9 } 10 /// <summary> 11 /// 初始化缓存 12 /// </summary> 13 private static List<UserToken> InitCache() 14 { 15 if (HttpRuntime.Cache[TOKENNAME] == null) 16 { 17 var tokens = _tokenRep.GetAll(); 18 // cache 的过期时间, 令牌过期时间 *2 19 HttpRuntime.Cache.Insert(TOKENNAME, tokens, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromDays(7 * 2)); 20 } 21 var ts = (List<UserToken>)HttpRuntime.Cache[TOKENNAME]; 22 return ts; 23 } 24 25 26 public static int GetUId(string token) 27 { 28 var tokens = InitCache(); 29 var result = 0; 30 if (tokens.Count > 0) 31 { 32 var id = tokens.Where(c => c.Token == token).Select(c => c.UId).FirstOrDefault(); 33 if (id != null) 34 result = id.Value; 35 } 36 return result; 37 } 38 39 40 public static string GetPermission(string token) 41 { 42 var tokens = InitCache(); 43 if (tokens.Count == 0) 44 return "NoAuthorize"; 45 else 46 return tokens.Where(c => c.Token == token).Select(c => c.Permission).FirstOrDefault(); 47 } 48 49 public static string GetUserType(string token) 50 { 51 var tokens = InitCache(); 52 if (tokens.Count == 0) 53 return ""; 54 else 55 return tokens.Where(c => c.Token == token).Select(c => c.UserType).FirstOrDefault(); 56 } 57 58 /// <summary> 59 /// 判断令牌是否存在 60 /// </summary> 61 /// <param></param> 62 /// <returns></returns> 63 public static bool IsExistToken(string token) 64 { 65 var tokens = InitCache(); 66 if (tokens.Count == 0) return false; 67 else 68 { 69 var t = tokens.Where(c => c.Token == token).FirstOrDefault(); 70 if (t == null) 71 return false; 72 else if (t.Timeout < DateTime.Now) 73 { 74 RemoveToken(t); 75 return false; 76 } 77 else 78 { 79 // 小于8小时 更新过期时间 80 if ((t.Timeout - DateTime.Now).TotalMinutes < 1 * 60 - 1) 81 { 82 t.Timeout = DateTime.Now.AddHours(8); 83 UpdateToken(t); 84 } 85 return true; 86 } 87 88 } 89 } 90 91 /// <summary> 92 /// 添加令牌, 没有则添加,有则更新 93 /// </summary> 94 /// <param></param> 95 public static void AddToken(UserToken token) 96 { 97 var tokens = InitCache(); 98 // 不存在 怎增加 99 if (!IsExistToken(token.Token)) 100 { 101 token.ID = 0; 102 tokens.Add(token); 103 // 插入数据库 104 _tokenRep.Add(token); 105 } 106 else // 有则更新 107 { 108 UpdateToken(token); 109 } 110 } 111 112 public static bool UpdateToken(UserToken token) 113 { 114 var tokens = InitCache(); 115 if (tokens.Count == 0) return false; 116 else 117 { 118 var t = tokens.Where(c => c.Token == token.Token).FirstOrDefault(); 119 if (t == null) 120 return false; 121 t.Timeout = token.Timeout; 122 // 更新数据库 123 var tt = _tokenRep.FindByToken(token.Token); 124 if (tt != null) 125 { 126 tt.UserType = token.UserType; 127 tt.UId = token.UId; 128 tt.Permission = token.Permission; 129 tt.Timeout = token.Timeout; 130 _tokenRep.Update(tt); 131 } 132 return true; 133 } 134 } 135 /// <summary> 136 /// 移除指定令牌 137 /// </summary> 138 /// <param></param> 139 /// <returns></returns> 140 public static void RemoveToken(UserToken token) 141 { 142 var tokens = InitCache(); 143 if (tokens.Count == 0) return; 144 tokens.Remove(token); 145 _tokenRep.Remove(token); 146 } 147 148 public static void RemoveToken(string token) 149 { 150 var tokens = InitCache(); 151 if (tokens.Count == 0) return; 152 153 var ts = tokens.Where(c => c.Token == token).ToList(); 154 foreach (var t in ts) 155 { 156 tokens.Remove(t); 157 var tt = _tokenRep.FindByToken(t.Token); 158 if (tt != null) 159 _tokenRep.Remove(tt); 160 } 161 } 162 163 164 public static void RemoveToken(int uid) 165 { 166 var tokens = InitCache(); 167 if (tokens.Count == 0) return; 168 169 var ts = tokens.Where(c => c.UId == uid).ToList(); 170 foreach (var t in ts) 171 { 172 tokens.Remove(t); 173 var tt = _tokenRep.FindByToken(t.Token); 174 if (tt != null) 175 _tokenRep.Remove(tt); 176 } 177 } 178 }

2. 新建ApiAuthorizeAttribute类,继承AuthorizeAttribute,重写方法IsAuthorized,这样基于TOKEN验证方式就完成了。实现如下: