你的位置:首页 > ASP.net教程

[ASP.net教程]Asp.Net Core 项目实战之权限管理系统(5) 用户登录

0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有

1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端

2 Asp.Net Core 项目实战之权限管理系统(2) 功能及实体设计

3 Asp.Net Core 项目实战之权限管理系统(3) 通过EntityFramework Core使用PostgreSQL

4 Asp.Net Core 项目实战之权限管理系统(4) 依赖注入、仓储、服务的多项目分层实现

5 Asp.Net Core 项目实战之权限管理系统(5) 用户登录

6 Asp.Net Core 项目实战之权限管理系统(6) 功能管理

github源码地址

0 TagHelper的使用

TagHelper是Asp.Net Core中提供的全新的服务端代码参与创建和渲染 HTML 元素的方法,TagHelpers 在 Razor视图中减少或避免了 HTML 和 C# 之间的显示转换,它具有以下特点:

  • 一种友好的Html开发体验

   Razor 标记使用 Tag Helpers 看起来更像标准的 HTML。熟悉 HTML/CSS/JavaScript 的前端设计师在没有学习 C# Razor 语法的情况下能够编辑 Razor 。

  • 提供丰富的智能感知环境来创建 HTML和Razor标记

   通过Microsoft.AspNetCore.Razor.Tools提供智能感知和智能提醒,大大提高编码效率。

  • 提供服务器端更强大,更可靠和可维护代码的html渲染方式

   TagHelper的使用一般放在“视图导入页”中,视图导入页中还会放置我们会用到的服务端引用。

0.0 创建视图导入页

在Fonour.MVC项目中,右键Views文件夹,添加新项,选择MVC视图导入页,添加一个默认名称为 “_ViewImports.cshtml”的视图导入页。

1

修改视图导入页的内容如下:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

0.1 使用Microsoft.AspNetCore.Razor.Tools

Microsoft.AspNetCore.Razor.Tools能够提供TagHelper的智能感知提示和代码加粗高亮显示。

  • 通过NuGet程序包管理器安装
  • 通过NuGet程序包控制台安装     
  • 直接修改project.json

最终在project.json文件中的dependencies及tools配置节中会出现Microsoft.AspNetCore.Razor.Tools

"dependencies": { "Microsoft.NETCore.App": "1.0.1", "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1", "Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.1", "Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.Extensions.Configuration": "1.0.0", "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0", "Fonour.Application": "1.0.0-*", "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", "Microsoft.AspNetCore.Session": "1.0.0", "Fonour.Utility": "1.0.0-*"},"tools": { "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final"},

打开Login/Index.cshtml文件,随意输入一个label标签,发现已经可以出现asp-for的TagHelper提示。

1

一个完整的使用TagHelper的label标签创建完成后,会以加粗高亮的方式显示。你自己可以根据喜好在 工具 > 选项 > 环境 > 字体和颜色 中自定义TagHelperElement的字体和颜色。更多关于TagHelper的使用,可以找专门的文章进行了解。

注意:如果安装完Microsoft.AspNetCore.Razor.Tools时不会出现智能提示,重启一下Visual Studio即可。

1 Asp.Net Core中Session中间件的使用

我们需要在用户登录以后记录当前登录用户的会话状态,ASP.NET Core 发布了一个关于会话的程序包,里面提供了用于管理会话状态的中间件。你可以在 project.json 中加入对Microsoft.AspNetCore.Session的引用来安装这个程序包。

1.0 Microsoft.AspNetCore.Session使用

0 Microsoft.AspNetCore.Session依赖项添加

通过NuGet程序包管理器、控制台、或直接修改project.json文件,添加对Microsoft.AspNetCore.Session中间件的引用。

1

1 修改Startup.cs文件的的ConfigureServices方法,增加Session服务注册

public void ConfigureServices(IServiceCollection services){  //获取数据库连接字符串  var sqlConnectionString = Configuration.GetConnectionString("Default");  //添加数据上下文  services.AddDbContext<FonourDbContext>(options =>options.UseNpgsql(sqlConnectionString));  services.AddScoped<IUserRepository, UserRepository>();  services.AddScoped<IUserAppService, UserAppService>();  services.AddMvc();  //Session服务  services.AddSession();}

2 修改Startup.cs文件的的Configure方法,请求管道中启用Session

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory){  loggerFactory.AddConsole();  if (env.IsDevelopment())  {    //开发环境异常处理    app.UseDeveloperExceptionPage();  }  else  {    //生产环境异常处理    app.UseExceptionHandler("/Shared/Error");  }  //使用静态文件  app.UseStaticFiles();  //Session  app.UseSession();  //使用Mvc,设置默认路由为系统登录  app.UseMvc(routes =>  {    routes.MapRoute(      name: "default",      template: "{controller=Login}/{action=Index}/{id?}");  });  SeedData.Initialize(app.ApplicationServices); //初始化数据}

1.1 Byte数组与对象转换帮助类ByteConvertHelper

Asp.Net Core中Session的Set方法必须提供一个Byte[]数组来存放对象,此外为了方便使用,还提供了SetString和SetInt32扩展方法。

void Set(string key, byte[] value);

我们在Fonour.Utility项目中增加一个Byte数组与对象互相转换的帮助类ByteConVertHelper。

public class ByteConvertHelper{  /// <summary>  /// 将对象转换为byte数组  /// </summary>  /// <param name="obj">被转换对象</param>  /// <returns>转换后byte数组</returns>  public static byte[] Object2Bytes(object obj)  {    string json = JsonConvert.SerializeObject(obj);    byte[] serializedResult = System.Text.Encoding.UTF8.GetBytes(json);    return serializedResult;  }  /// <summary>  /// 将byte数组转换成对象  /// </summary>  /// <param name="buff">被转换byte数组</param>  /// <returns>转换完成后的对象</returns>  public static object Bytes2Object(byte[] buff)  {    string json = System.Text.Encoding.UTF8.GetString(buff);    return JsonConvert.DeserializeObject<object>(json);  }  /// <summary>  /// 将byte数组转换成对象  /// </summary>  /// <param name="buff">被转换byte数组</param>  /// <returns>转换完成后的对象</returns>  public static T Bytes2Object<T>(byte[] buff)  {    string json = System.Text.Encoding.UTF8.GetString(buff);    return JsonConvert.DeserializeObject<T>(json);  }}

2 用户登录实现

有了以上准备工作,我们可以开始正式实现用户登录功能了。

2.0 Model

在Fonour.MVC项目中增加一个Models文件夹,用于存放前端交互使用的Model类,在Models文件夹下新建一个LoginModel类,并通过DataAnnotations特性指定属性的验证信息。

public class LoginModel {   [Required(ErrorMessage = "用户名不能为空。")]   public string UserName { get; set; }   [Required(ErrorMessage = "密码不能为空。")]   [DataType(DataType.Password)]   public string Password { get; set; }   public bool RememberMe { get; set; } }

在视图导入页_ViewImport.cshtml中增加对模型的引用

@using Fonour.MVC.Models

2.1 View

使用TagHelper修改Login/Index.cshtml为如下内容

@{  Layout = null;[email protected] LoginModel<!DOCTYPE html><html><head>  <title>系统登录</title>  <!-- Tell the browser to be responsive to screen width -->  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">  <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css">  <link rel="stylesheet" href="~/lib/font-awesome/css/font-awesome.css">  <link rel="stylesheet" href="~/css/AdminLTE.css">  <link rel="stylesheet" href="~/lib/iCheck/skins/square/blue.css"></head><body class="hold-transition login-page">  <div class="login-box">    <div class="login-logo">      <a href="http://fonour.cnblogs.com" target="_blank"><b>Fonour</b></a>    </div>    <!-- /.login-logo -->    <div class="login-box-body">      <p class="login-box-msg">权限管理系统</p>      <div asp-validation-summary="All" class="text-danger"></div>      <form asp-controller="Login" asp-action="Index" method="post">        <div class="form-group has-feedback">          <input asp-for="UserName" type="text" class="form-control" placeholder="用户名">          <span class="glyphicon glyphicon-user form-control-feedback"></span>          <span asp-validation-for="UserName" class="text-danger"></span>        </div>        <div class="form-group has-feedback">          <input asp-for="Password" type="password" class="form-control" placeholder="密码">          <span class="glyphicon glyphicon-lock form-control-feedback"></span>        </div>        <div class="row">          <div class="col-xs-8">            <div class="checkbox icheck">              <label>                <input asp-for="RememberMe" type="checkbox"> 记住我              </label>            </div>          </div>          <!-- /.col -->          <div class="col-xs-4">            <button type="submit" class="btn btn-primary btn-block btn-flat">登录</button>          </div>          <!-- /.col -->        </div>      </form>    </div>    <!-- /.login-box-body -->  </div>  <!-- /.login-box -->  <script src="~/lib/jquery/dist/jquery.js"></script>  <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>  <script src="~/lib/iCheck/icheck.js"></script>  <script>    $(function () {      $('input').iCheck({        checkboxClass: 'icheckbox_square-blue',        radioClass: 'iradio_square-blue',        increaseArea: '20%' // optional      });    });  </script></body></html>

关键说明

  • @model LoginModel  指定页面绑定的模型为LoginModel。
  • asp-controller 指定form标签提交时对应的控制器名称。
  • asp-action 指定form标签提交时对应的Action名称。
  • asp-for 指定HTML元素绑定的模型对应的属性名称。
  • asp-validation-for 绑定对应模型属性名称,模型验证失败时,显示模型定义的ErrorMessage。
  • asp-validation-summary="All" 显示所有验证失败的错误信息。

2.2 Controller

修改LoginController,增加用户登录对应的控制器方法。

[HttpPost]public IActionResult Index(LoginModel model){  if (ModelState.IsValid)  {    //检查用户信息     var user = _userAppService.CheckUser(model.UserName, model.Password);    if (user != null)    {      //记录Session      HttpContext.Session.Set("CurrentUser", ByteConvertHelper.Object2Bytes(user));      //跳转到系统首页       return RedirectToAction("Index", "Home");    }    ModelState.AddModelError("", "用户名或密码错误。");    return View();  }  return View(model);}

到此我们基本上就完成了用户登录的逻辑,以及服务器端的登录验证。当输入用户名、密码信息不符合条件时,会给出详细的错误提示。

1

2

2.3 验证信息美化、记住我功能的实现

上面我们只做了服务端验证,而且错误信息的提示并不是很美观,我们可以根据需要修改样式对错误提示信息进行美化。我这里直接使用Layer.js这个前端库。

验证信息美化

修改用户登录控制器方法,有错误信息时只返回第一条错误信息,客户端自行处理错误信息。

[HttpPost] public IActionResult Index(LoginModel model) {   if (ModelState.IsValid)   {     //检查用户信息     var user = _userAppService.CheckUser(model.UserName, model.Password);     if (user != null)     {       //记录Session       HttpContext.Session.Set("CurrentUser", ByteConvertHelper.Object2Bytes(user));       //跳转到系统首页       return RedirectToAction("Index", "Home");     }     ViewBag.ErrorInfo = "用户名或密码错误。";     return View();   }   ViewBag.ErrorInfo = ModelState.Values.First().Errors[0].ErrorMessage;   return View(model); }

通过Bower程序包管理器添加对Layer的引用,在Login/Index.cshtml中增加对layer.js的引用

<script src="~/lib/layer/layer.js"></script>

增加一个隐藏的input标签用于记录错误信息。

<input id="errorInfo" type="hidden" value="@ViewBag.ErrorInfo" />

初始化完成后增加对错误信息的处理。

<script>  $(function () {    $('input').iCheck({      checkboxClass: 'icheckbox_square-blue',      radioClass: 'iradio_square-blue',      increaseArea: '20%' // optional    });    //显示服务端验证的错误信息     if ($("#errorInfo").val()) {      layer.tips($("#errorInfo").val(), "#btnLogin");    };  });</script>

此时运行程序,服务器端错误信息的展示样式已经比较美观了。

1

记住我

记住我,主要是记录输入的用户名及密码,通过cookie保存,首先通过Bower前端包管理器增加Jquery.Cookie的引用。在Login/Index.cshtml中增加对jquery.cookie.js的引用。

<script src="~/lib/jquery.cookie/src/jquery.cookie.js"></script>

增加form的onsubmit方法

<form asp-controller="Login" asp-action="Index" method="post" onsubmit="onSubmit()">

<script>  $(function () {    $('input').iCheck({       checkboxClass: 'icheckbox_square-blue',      radioClass: 'iradio_square-blue',      increaseArea: '20%' // optional    });        //显示服务端验证的错误信息    if ($("#errorInfo").val()) {      layer.tips($("#errorInfo").val(), "#btnLogin");    };    //判断之前是否有设置cookie,如果有,则设置【记住我】选择框    if ($.cookie("fonour_userName") != undefined) {      $("#RememberMe").attr("checked", "checked");    }    else {      $("#RememberMe").removeAttr("checked");    }    //读取cookie    if ($("#RememberMe:checked").length > 0) {      $("#UserName").val($.cookie("fonour_userName"));      $("#Password").val($.cookie("fonour_password"));    }  });  //根据是否勾选记住我记录或清除cookie  function onSubmit() {    if ($("#RememberMe:checked").length > 0) {//设置cookie      $.cookie("fonour_userName", $("#UserName").val());      $.cookie("fonour_password", $("#Password").val());    } else {//清除cookie      $.removeCookie("fonour_userName");      $.removeCookie("fonour_password");    }  };</script>

输入用户名密码登陆后,再次回到登录界面,会发现用户名及密码已经填充。

3 用户是否登录控制器拦截

一个最基本的控制器拦截,就是当我们直接通过在地址栏输入访问路由地址时,首先应该判断用户是否已经登录,如果没有登录应该实现跳转到登录页面。大致思路是通过重写Controller的OnActionExecuting方法,在OnActionExecuting方法中判断用户是否登录并实现跳转。

3.1 新建控制器基类

在Fonour.MVC中右键Controllers文件夹,添加一个名称为FonourControllerBase的控制器基类,内容如下。

public abstract class FonourControllerBase : Controller{  public override void OnActionExecuting(ActionExecutingContext filterContext)  {    byte[] result;     filterContext.HttpContext.Session.TryGetValue("CurrentUser",out result);    if (result == null)    {      filterContext.Result = new RedirectResult("/Login/Index");      return;    }    base.OnActionExecuting(filterContext);  }}

需要进行登陆验证的控制器,修改为从FonourControllerBase继承,这里我们修改HomeController

public class HomeController : FonourControllerBase

启动程序,在未登录情况下,通过地址栏直接访问/Home/Index,会发现已经自动跳转到系统登录界面。

4 总结

本次主要介绍了TagHelper的简单实用;Asp.Net Core中的Session中间件的使用;以及系统登录的服务端验证,并对控制器的访问进行了统一的是否登录验证拦截。下一节主要进行功能管理的实现。


深圳有什么好玩的地方深圳自助游景点攻略大全深圳旅游需要多少钱广东深圳旅游景点深圳去深圳旅游要多少钱老建筑里寻宁静 探访徐州户部山民居 广州到从化千泷沟大瀑布开车怎么走?广州到从化千泷沟大瀑布有多远? 千泷沟大瀑布一日游攻略?从化千泷沟大瀑布什么时候最好玩? 千泷沟大瀑布自驾游攻略?从化千泷沟大瀑布开车怎么走? 为什么没有男朋友 天津的妹纸真相了(组图) 火车狂迷 盘点沈阳四大名站 金庸笔下十大旅游胜地 刀光剑影的美(组图) 南京香格里拉大酒店10月27日全新开幕 南粤石文化博览园怎样去?中山怎么去南粤石文化博览园? 石根山风景区在哪里?信宜石根山风景区旅游攻略? 石根山风景旅游区电话?信宜石根山风景旅游区门票多少钱? 石根山风景旅游区好玩吗?信宜石根山风景旅游区怎么样? 三寨谷度假村景点电话?南昆三寨谷度假村门票包含哪些景点? 龙门三寨谷电话?惠州龙门三寨谷门票预订? 昆明青龙峡 让你告别宅神投身自然 佛冈观音山王山寺团购价格?观音山王山寺门票团购多少钱? Q65110A9090 Datasheet Q65110A9090 Datasheet Q65110A9093 Datasheet Q65110A9093 Datasheet Q65110A9105 Datasheet Q65110A9105 Datasheet 香港女人街 香港女人街 香港女人街 北京胡同游攻略 北京胡同游攻略 北京胡同游攻略 香港夜景 香港夜景 香港夜景