zoukankan      html  css  js  c++  java
  • 构建NetCore应用框架之实战篇(七):BitAdminCore框架登录功能源码解读

    本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性。

    构建NetCore应用框架之实战篇系列

    一、简介


    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();
            }
        }
    }

    本篇代码解读到此,接下来怎么接着写,需要思考一段时间了,连续写太多,有些思路不清晰。

  • 相关阅读:
    mysql性能调优与架构设计(一)商业需求与系统架构对性能的影响
    Android发送数据到web服务器4种方式
    Java 操作mongodb
    父子容器互相操作的方法
    Sql Server中查询当天,最近三天,本周,本月,最近一个月,本季度的数据的sql语句
    js实现多少秒后自动跳转
    插入数据返回插入的主键Id
    日期比较
    Cookie的增删改查
    js标准化价钱
  • 原文地址:https://www.cnblogs.com/chenyinxin/p/9018689.html
Copyright © 2011-2022 走看看