在開始寫本節內容前,我使用Nancy.Authentication.Token實現的Token認證,可是就在我開始寫本節內容的時,我看到Nancyfx的文檔中的內容更新sql
因此我改成使用Nancy.Authentication.Stateless本身實現Token認證api
從上一節中的WebSite項目中拷貝如下幾個文件,修改命名空間,修改Bootstrapper去掉Form認證的相關代碼緩存
using System.Collections.Generic; using Nancy.Security; using Nop.Core.Caching; namespace WebSite.WebApi.Models { /// <summary> /// 表明通過認證的用戶 /// </summary> public class UserIdentity : IUserIdentity { public UserIdentity(string userName) : this(userName, new List<string>()) { } public UserIdentity(string userName, IEnumerable<string> claims) { this.UserName = userName; this.Claims = claims; } public IEnumerable<string> Claims { get; private set; } public string UserName { get; private set; } } /// <summary> /// 包含生成token和校驗token的靜態方法 /// </summary> public class UserMapper { private static readonly MemoryCacheManager manager = new MemoryCacheManager(); /// <summary> /// 根據token獲取用戶信息,檢測用戶是否有效 /// </summary> /// <param name="token"></param> /// <returns></returns> public static IUserIdentity GetUserFromAccessToken(string token) { if (string.IsNullOrEmpty(token)) { return null; } return manager.Get<UserIdentity>(token); } /// <summary> /// 生成一個新的token,並緩存 /// </summary> /// <param name="userName"></param> /// <returns></returns> public static string GenerateToken(string userName) { string token= Guid.NewGuid().ToString(); //token有效期 manager.Set(token, new UserIdentity(userName),60*24); return token; } } }
pipelines.AfterRequest.AddItemToEndOfPipeline(x => { x.Response.Headers.Add("Access-Control-Allow-Origin", "*"); x.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT,OPTIONS"); }); var configuration =new StatelessAuthenticationConfiguration(nancyContext => { //返回null代碼token無效或用戶未認證 string token = nancyContext.Request.Headers.Authorization; if (!string.IsNullOrEmpty(token)) { return UserMapper.GetUserFromAccessToken(token); } else { return null; } }); StatelessAuthentication.Enable(pipelines, configuration);
/// <summary> /// Gets the User by identifier. /// </summary> /// <returns>The User by identifier.</returns> /// <param name="id">Identifier.</param> public virtual User GetUserById(int id) { if (id == 0) return null; string key = string.Format(Users_BY_ID_KEY, id); var user = _cacheManager.Get(key, () => userRepository.GetById(id)); return user; }
private IUserService service; public AuthController(IUserService service) : base("token") { this.service = service; Post["/"] = x => { var user = this.Bind<User>(); return GetToken(user.UserName, user.Password); }; } private object GetToken(string username, string password) { DataResult<User> result = service.ValidateUser(username, password); if (result.Result == 0) { return new { error = "認證失敗!", error_description = result.Message, }; } else { return new { access_token = UserMapper.GenerateToken(username), }; } }
public class UserController:NancyModule { private IUserService service; public UserController(IUserService service):base("api/user") { //限制認證 this.RequiresAuthentication(); this.service = service; //異步模型 Get["/{Id}", true] = async (_, ct) => { User user = await Task.Run(() => { return service.GetUserById(_.Id); }); return user; }; } }
RestClient client = new RestClient("http://localhost:56751"); string result = string.Empty; var request = new RestRequest("/token"); var body = new { grant_type = "password", username = "admin", password = "1234567" }; request.AddObject(body); IRestResponse response = client.Post(request); result = response.Content; dynamic content = SimpleJson.DeserializeObject(result); ; if (response.StatusCode != HttpStatusCode.OK) { string error = content.error_description; return; } string token = content.access_token; var request2 = new RestRequest("/api/user/1"); request2.AddHeader("Authorization", token); IRestResponse response2 = client.Get(request2); if (response2.StatusCode == HttpStatusCode.OK) { result = response2.Content; }