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

构建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();
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 = , 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 = , Msg = "验证码不正确,请重新输入!" }); if (!SSOClient.Validate(account, password, out Guid userId))
return Json(new { Code = , Msg = "帐号或密码不正确,请重新输入!" }); HttpContextCore.Current.Session.Set("VerificationCode", string.Empty); SSOClient.SignIn(userId);
return Json(new { Code = });
}
catch (Exception ex)
{
LogHelper.SaveLog(ex);
return Json(new { Code = , 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 = , Msg = "服务器异常,请联系管理员!" });
}
} /// <summary>
/// 登出
/// </summary>
/// <returns></returns>
public ActionResult SignOut()
{
SSOClient.SignOut();
return Json(new { Code = });
}
}
}

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

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

构建NetCore应用框架之实战篇(七):BitAdminCore框架登录功能源码解读的更多相关文章

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

    构建NetCore应用框架之实战篇 构建NetCore应用框架之实战篇(一):什么是框架,如何设计一个框架 构建NetCore应用框架之实战篇(二):BitAdminCore框架定位及架构 构建Net ...

  2. 构建NetCore应用框架之实战篇(三):BitAdminCore框架功能规划选择

    本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.BitAdminCore功能规划 如何选择框架的落地功能,前篇文章 ...

  3. 构建NetCore应用框架之实战篇(六):BitAdminCore框架架构小结

    本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.小结 1.前面已经完成框架的第一个功能,本篇做个小结. 2.直接上 ...

  4. 构建NetCore应用框架之实战篇(五):BitAdminCore框架1.0登录功能设计实现及源码

    本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.设计原则 1.继承前面框架架构思维,设计以可读性作为首要目标. 2 ...

  5. 构建NetCore应用框架之实战篇(四):BitAdminCore框架1.0登录功能细化及技术选型

    本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.BitAdminCore框架1.0版本 1.1.0版本是指最小版本 ...

  6. 构建NetCore应用框架之实战篇(二):BitAdminCore框架定位及架构

    本篇承接上篇内容,如果你不小心点击进来,建议重新从第一篇开始完整阅读. 构建NetCore应用框架之实战篇索引 一.BitAdminCore框架简介 从前篇论述我们知道,我们接下来将要去做一个管理系统 ...

  7. 如何在Visual Studio 2017中使用C# 7+语法 构建NetCore应用框架之实战篇(二):BitAdminCore框架定位及架构 构建NetCore应用框架之实战篇系列 构建NetCore应用框架之实战篇(一):什么是框架,如何设计一个框架 NetCore入门篇:(十二)在IIS中部署Net Core程序

    如何在Visual Studio 2017中使用C# 7+语法   前言 之前不知看过哪位前辈的博文有点印象C# 7控制台开始支持执行异步方法,然后闲来无事,搞着,搞着没搞出来,然后就写了这篇博文,不 ...

  8. 构建NetCore应用框架之实战篇(一):什么是框架,如何设计一个框架

    一.系列简述 本篇起,将通过一系列文章,去描述如何构建一个应用开发框架,并以作者开发的框架为例,逐个点展开分析,如何从零开始,构建自己的开发框架. 本系列文章的目的,是带领有一编程经验的人,通过动手, ...

  9. Android网络框架Volley(实战篇)

      之前讲了ym—— Android网络框架Volley(体验篇),大家应该了解了volley的使用,接下来我们要看看如何把volley使用到实战项目里面,我们先考虑下一些问题: 从上一篇来看 mQu ...

随机推荐

  1. 二叉树中的最大路径和 · Binary Tree Maximum Path Sum

    [抄题]: 给出一棵二叉树,寻找一条路径使其路径和最大,路径可以在任一节点中开始和结束(路径和为两个节点之间所在路径上的节点权值之和) [思维问题]: 不会写分合法 [一句话思路]: 用两次分治:ro ...

  2. [leetcode]257. Binary Tree Paths二叉树路径

    Given a binary tree, return all root-to-leaf paths. Note: A leaf is a node with no children. Example ...

  3. 让php支持多线程,win下安装pthreads

    1.检查PHP版本是否支持线程安全 在phpinfo()的显示页中,搜索Thread Safety,如果是enabled,则PHP版本是线程安全的. 2.在http://windows.php.net ...

  4. JSP标准标签库JSTL

    1.什么是JSTL? JSP标准标签库(JSP Standard Tag Library) 2.JSTL标准标签库中的常用标签 JSTL是JSP页面的标签库,实质上是一段Java代码.我们常用的是它的 ...

  5. linux-centos6-rabbitmq安装及配置

    服务器版本centos6.8 一.先安装Erlang 具体安装哪个版本可以对照 http://www.rabbitmq.com/which-erlang.html 如下图: 准备安装RabbitMQ3 ...

  6. C#设计模式之简单工厂模式(过渡模式)

    一.引言 之所以写这个系列,是了为了自己更好的理解设计模式,也为新手提供一些帮助,我都是用最简单的.最生活化的实例来说明.在上一篇文章中讲解了单例模式,今天就给大家讲一个比较简单的模式——简单工厂模式 ...

  7. Laravel5.5 使用队列 Queue

    使用队列# 上一章节中我们开发了自动生成 Slug 功能,但是因为我们的需要实时请求百度翻译接口,这将会是一个系统性能隐患. 一般情况下,网络请求会存在各种不确定性,如果请求 API 出现超时情况,或 ...

  8. 分组取前N记录

    分组取前N记录   经常看到问题,如何取出每组的前N条记录.方便大家参考于是便把常见的几种解法列出于下. 问题:有表 如下,要求取出各班前两名(允许并列第二)Table1+----+------+-- ...

  9. 内建类型,与用户自定义类型,返回值为const

    1对内建类型来说,按值返回的是否为const,是无关紧要的,因为编译器已经不让它成为一个坐直,因为它总是一个值,而不是一个变量(thing in c++ page192) 2当处理用户自定义的类型时, ...

  10. HDU 1009 FatMouse' Trade (贪心算法)

    题意:就是老鼠要用猫粮换粮食,第i个房间一些东西,要用东西去换,可以不全换.问给定的猫粮最多能换多少粮食. 析:贪心算法.我们先算出来每个房间物品的平均价格是多少,肯定越低越好,并且如果能全换就全换, ...