构建NetCore应用框架之实战篇(七):BitAdminCore框架登录功能源码解读
程序员文章站
2022-08-19 15:30:12
本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性。 构建NetCore应用框架之实战篇系列 一、简介 1、登录功能完成后,框架的雏形已经形成,有必要进行复习。 2、本篇简单对框架代码进行一些解释。同时可以简单理解框架的规范。 二、目录结构规范 1、直接上图,目录 ......
本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性。
一、简介
1、登录功能完成后,框架的雏形已经形成,有必要进行复习。
2、本篇简单对框架代码进行一些解释。同时可以简单理解框架的规范。
二、目录结构规范
1、直接上图,目录结构已经包含规范,哪类文件该放哪里。
三、Startup中的代码功能解释
1、想了很多办法,最终还是觉得用注释的方式,请细读文中注释。
2、见代码
namespace BitAdminCoreLearn { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //注册Session服务 services.AddSession(); //注册HttpContext单例,这个HttpContextCore.Current要用到,不注册取出来是null。 services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); //使用登录认证 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => options.TicketDataFormat = new TicketDataFormat<AuthenticationTicket>()); services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider svc) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //使用配置信息,就是一个静态变量付值。 HttpContextCore.Configuration = this.Configuration; HttpContextCore.ServiceProvider = svc; HttpContextCore.HostingEnvironment = env; //启用静态文件 app.UseStaticFiles(); //启用Session缓存 app.UseSession(); //启用登录认证服务 app.UseAuthentication(); //使用自定义路由模版 app.UseMvc(routes => routes.MapRoute(name: "default", template: "{controller=Account}/{action=Index}/{id?}")); } } /// <summary> /// 这个是自定义Ticket加密解密类。 /// 功能:实现负责均衡支持,虽然Cookie模式,默认实现会与服务器绑定,服务器A产生的Cookies无法在服务器B解释。 /// 应用:登录组件在加解密Cookies时会调用本方法,具体见services.AddAuthentication /// </summary> /// <typeparam name="T"></typeparam> public class TicketDataFormat<T> : ISecureDataFormat<T> where T : AuthenticationTicket { public string Protect(T data, string purpose) { TicketSerializer _serializer = new TicketSerializer(); byte[] userData = _serializer.Serialize(data); return Convert.ToBase64String(userData); } public T Unprotect(string protectedText, string purpose) { TicketSerializer _serializer = new TicketSerializer(); byte[] bytes = Convert.FromBase64String(protectedText); return _serializer.Deserialize(bytes) as T; } string ISecureDataFormat<T>.Protect(T data) { TicketSerializer _serializer = new TicketSerializer(); byte[] userData = _serializer.Serialize(data); return Convert.ToBase64String(userData); } T ISecureDataFormat<T>.Unprotect(string protectedText) { TicketSerializer _serializer = new TicketSerializer(); byte[] bytes = Convert.FromBase64String(protectedText); return _serializer.Deserialize(bytes) as T; } } /// <summary> /// 这里是自定义权限过滤器。 /// 功能:如果未登录,返回405 /// 应用:如果api定义了过滤,会运行以下代码,需要登录才能访问 /// 前端:前端ajax有全局设置,跳转到登录页。 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class BitAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { if (!SSOClient.IsLogin) { context.Result = new StatusCodeResult((int)HttpStatusCode.MethodNotAllowed); } } } }
四、AccountController中的代码功能解释
1、上代码、见注释。
namespace BitAdminCore.Controllers { public class AccountController : Controller { DataContext dbContext = new DataContext(); /// <summary> /// 首页跳转,当用户输入域名时,可以路转到登录页,而不会出现错误。 /// </summary> /// <returns></returns> public ActionResult Index() { return Redirect("/pages/account/login.html"); } /// <summary> /// 判断是否登录,前端每个页面加载时,都会进行判断。 /// 登录页:如果已登录,跳转到首页。 /// 其它页:如果未登录,跳转到登录页。 /// </summary> /// <returns></returns> public JsonResult IsLogin() { return Json(Convert.ToString(SSOClient.IsLogin).ToLower()); } /// <summary> /// 验证码,直接返回image类型,把路径写在src上即可 /// </summary> /// <returns></returns> public ActionResult VerifyCode() { try { string code = VerificationCode.CreateCode(4); Bitmap image = VerificationCode.CreateImage(code); MemoryStream ms = new MemoryStream(); image.Save(ms, ImageFormat.Png); byte[] bytes = ms.GetBuffer(); ms.Close(); HttpContextCore.Current.Session.Set("VerificationCode", code); return File(bytes, "image/jpeg"); } catch (Exception ex) { LogHelper.SaveLog(ex); return Json(new { Code = 1, Msg = "服务器异常,请联系管理员!" }); } } /// <summary> /// 登录验证方法,你懂的 /// </summary> /// <param name="account"></param> /// <param name="password"></param> /// <param name="verifyCode"></param> /// <returns></returns> public JsonResult Login(string account, string password,string verifyCode) { try { string vcode = HttpContextCore.Current.Session.Get<string>("VerificationCode"); if (Convert.ToString(verifyCode).ToLower() != Convert.ToString(vcode).ToLower()) return Json(new { Code = 1, Msg = "验证码不正确,请重新输入!" }); if (!SSOClient.Validate(account, password, out Guid userId)) return Json(new { Code = 1, Msg = "帐号或密码不正确,请重新输入!" }); HttpContextCore.Current.Session.Set("VerificationCode", string.Empty); SSOClient.SignIn(userId); return Json(new { Code = 0 }); } catch (Exception ex) { LogHelper.SaveLog(ex); return Json(new { Code = 1, Msg = "服务器异常,请联系管理员!" }); } } /// <summary> /// 登录后获取当前用户信息,首页会用到。 /// 这里需要登录后才能调用,所以加了过滤。 /// </summary> /// <returns></returns> [BitAuthorize] public JsonResult GetUser() { try { SysUser user = SSOClient.User; //SysDepartment department = SSOClient.Department; return Json(new { userCode = Convert.ToString(user.UserCode), userName = Convert.ToString(user.UserName), idCard = Convert.ToString(user.IdCard), mobile = Convert.ToString(user.Mobile), email = Convert.ToString(user.Email), //departmentName = Convert.ToString(department.DepartmentName) }); } catch (Exception ex) { LogHelper.SaveLog(ex); return Json(new { Code = 1, Msg = "服务器异常,请联系管理员!" }); } } /// <summary> /// 登出 /// </summary> /// <returns></returns> public ActionResult SignOut() { SSOClient.SignOut(); return Json(new { Code = 0 }); } } }
五、SSOClient中的代码功能解释
1、上代码、见注释。
namespace BitAdminCore.Helpers { public partial class SSOClient { public static bool IsLogin { get { if (HttpContextCore.Current.User == null || HttpContextCore.Current.User.Identity == null) return false; return HttpContextCore.Current.User.Identity.IsAuthenticated; } } /// <summary> /// 通过用户名密码验证用户信息,如果成功,返回用户ID,供系统默认登录使用。 /// </summary> /// <param name="sign"></param> /// <param name="password"></param> /// <param name="userid"></param> /// <returns></returns> public static bool Validate(string sign, string password,out Guid userid) { userid = Guid.Empty; DataContext dbContext = new DataContext(); password = EncryptHelper.MD5(password); var userModel = dbContext.SysUser.FirstOrDefault(t => (t.Mobile == sign || t.Email == sign || t.UserCode == sign) && t.UserPassword == password); if (userModel == null) return false; userid = userModel.UserId; return true; } /// <summary> /// 通过用户标识验证用户。不需要密码,通常是第三方登录之后,返回标识,再通过标识验证。 /// </summary> /// <param name="sign"></param> /// <param name="user"></param> /// <returns></returns> public static bool Validate(string sign, out SysUser user) { DataContext dbContext = new DataContext(); user = dbContext.SysUser.FirstOrDefault(t => (t.Mobile == sign || t.Email == sign || t.UserCode == sign) ); if (user == null) return false; return true; } /// <summary> /// 登录函数,写入登录状态和登录信息。 /// 这里需要在Startup中的那些配置项(具体机制后续写一篇文章介绍)。 /// </summary> /// <param name="userid"></param> public static void SignIn(Guid userid) { DataContext dbContext = new DataContext(); SysUser user = dbContext.SysUser.FirstOrDefault(x => x.UserId == userid); //var roles = dbContext.SysRoleUser.Where(x => x.UserId == user.UserId).ToList(); ClaimsIdentity identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Sid, user.UserId.ToString())); identity.AddClaim(new Claim(ClaimTypes.Name, user.UserCode)); //foreach (var role in roles) //{ // identity.AddClaim(new Claim(ClaimTypes.Role, role.RoleId.ToString())); //} SignOut(); HttpContextCore.Current.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity)); } /// <summary> /// 登出,也就是清除登录Cookies和Session /// </summary> public static void SignOut() { HttpContextCore.Current.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); HttpContextCore.Current.Session.Clear(); } } }
本篇代码解读到此,接下来怎么接着写,需要思考一段时间了,连续写太多,有些思路不清晰。
下一篇: 抖音feed流正在疯狂收割
推荐阅读
-
构建NetCore应用框架之实战篇(四):BitAdminCore框架1.0登录功能细化及技术选型
-
构建NetCore应用框架之实战篇(五):BitAdminCore框架1.0登录功能设计实现及源码
-
构建NetCore应用框架之实战篇(七):BitAdminCore框架登录功能源码解读
-
构建NetCore应用框架之实战篇(三):BitAdminCore框架功能规划选择
-
构建NetCore应用框架之实战篇(四):BitAdminCore框架1.0登录功能细化及技术选型
-
构建NetCore应用框架之实战篇(五):BitAdminCore框架1.0登录功能设计实现及源码
-
构建NetCore应用框架之实战篇(三):BitAdminCore框架功能规划选择
-
构建NetCore应用框架之实战篇(七):BitAdminCore框架登录功能源码解读