asp.net core后台系统登录的快速构建

登录流程图

示例预览

构建步骤

当然,你也可以直接之前前往coding仓库查看源码,要是发现bug记得提醒我啊~ LoginDemo地址

1. 首先你得有一个项目

2. 然后你需要一个登录页面

完整Login.cshtml视图代码戳这里-共计55行 效果预览图

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>登录界面</title>
    <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <style type="text/css">
        body { color: #fff; font-family: "微软雅黑"; font-size: 14px; background: url('https://dn-coding-net-production-pp.qbox.me/96ec8cc7-0e5f-4217-b853-4a88c15579f3.png') no-repeat; }
        .wrap1 { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; height: 450px; }
        /*把整个屏幕真正撑开--而且能自己实现居中*/
        .main_content { background: url(https://dn-coding-net-production-pp.qbox.me/2ed70a05-04ad-4ccf-81d4-bc1fad2b6e41.png) repeat; margin-left: auto; margin-right: auto; text-align: left; float: none; border-radius: 8px; }
        .form-group { position: relative; }
        .login_btn { display: block; background: #3872f6; color: #fff; font-size: 15px; width: 100%; line-height: 50px; border-radius: 3px; border: none; }
        .login_input { width: 100%; border: 1px solid #3872f6; border-radius: 3px; line-height: 40px; padding: 2px 5px 2px 30px; background: none; }
        .icon_font { position: absolute; top: 12px; left: 10px; font-size: 18px; color: #3872f6; }
        .font16 { font-size: 16px; }
        .mg-t20 { margin-top: 20px; }
        @media (min-width:200px) {.pd-xs-20 { padding: 20px; }}
        @media (min-width:768px) {.pd-sm-50 { padding: 50px; }}
        #grad { background: -webkit-linear-gradient(#4990c1, #52a3d2, #6186a3); /* Safari 5.1 - 6.0 */ background: -o-linear-gradient(#4990c1, #52a3d2, #6186a3); /* Opera 11.1 - 12.0 */ background: -moz-linear-gradient(#4990c1, #52a3d2, #6186a3); /* Firefox 3.6 - 15 */ background: linear-gradient(#4990c1, #52a3d2, #6186a3); /* 标准的语法 */ }
        /*==jquery.validate css==*/
        .field-validation-error { color: #e14430 !important; padding-top: 5px; }
        .input-validation-error { border-color: #d38e99; }
    </style>
</head>
<body>
    <div class="container wrap1">
        <h2 class="mg-b20 text-center">后台管理系统</h2>
        <div class="col-sm-8 col-md-5 center-auto pd-sm-50 pd-xs-20 main_content">
            <p class="text-center font16">用户登录</p>
            <form asp-action="Login" method="post" >
                <div class="form-group mg-t20">
                    <i class="icon_font glyphicon glyphicon-user"></i>
                    <input type="text" class="login_input" asp-for="UserName" placeholder="请输入用户名" autofocus />
                    <span asp-validation-for="UserName"></span>
                </div>
                <div class="form-group mg-t20">
                    <i class="icon_font glyphicon glyphicon-lock"></i>
                    <input type="password" class="login_input" asp-for="UserPwd" placeholder="请输入密码" />
                    <span asp-validation-for="UserPwd"></span>
                </div>
                <div class="checkbox mg-b25 hide">
                    <label>
                        <input type="checkbox">记住我的登录信息
                    </label>
                </div>
                <button type="submit" class="login_btn">登 录</button>
            </form>
        </div>
    </div>
</body>
</html>

3. 然后你需要一个登录的控制器AccountController

控制器里面至少拥有一个呈现登录页的action,一个接收登录请求的action,一个退出的action ·登录· 判断是否存在用户,将用户名或者用户ID加密后记录到cookie中,跳转到管理页 ·退出· 将cookie移出掉,跳转到登录页 加密的方法可自行切换为其他的加密方法

    public class AccountController : Controller
    {
        private readonly IUserService _userService;
        public AccountController(IUserService userService)
        {
            _userService = userService;
        }

        public IActionResult Login()
        {
            return View();
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Login(AccountModel model)
        {
            //验证模型是否正确
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            //调用服务验证用户名密码
            if (!_userService.Login(model.UserName, model.UserPwd))
            {
                ModelState.AddModelError(nameof(model.UserPwd), "用户名或密码错误");
                return View();
            }
            //加密用户名写入cookie中,AdminAuthorizeAttribute特性标记取出cookie并解码除用户名
            var encryptValue = _userService.LoginEncrypt(model.UserName, ApplicationKeys.User_Cookie_Encryption_Key);
            HttpContext.Response.Cookies.Append(ApplicationKeys.User_Cookie_Key, encryptValue);
            return Redirect("/");
        }
        public IActionResult Logout()
        {
            HttpContext.Response.Cookies.Delete(ApplicationKeys.User_Cookie_Key);
            return Redirect(WebContext.LoginUrl);
        }
    }

4. 然后还需要一个身份验证的特性标记AdminAuthorizeAttribute

本文只是简单的验证是否登录,关于更复杂的权限验证可参考文章:http://www.cnblogs.com/morang/p/7606843.html,以及示例项目 将此特性标记加到需要的地方即可在访问时验证用户是否登录,未登录则跳转到登录页。

    public class AdminAuthorizeAttribute : Attribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext filterContext)
        {
            if (string.IsNullOrEmpty(WebContext.AdminName))
            {
                if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
                {
                    filterContext.Result = new JsonResult("未登录");
                }
                else
                {
                    filterContext.Result = new RedirectResult("Account/Login");
                }
                return;
            }
        }
    }

上面特性标记代码中的WebContext.AdminName是如何取到的呢?还需要结合如下代码

    //服务定位器
    public static class ServiceLocator
    {
        public static IServiceProvider Instance { get; set; }
        public static T GetService<T>() where T : class
        {
            return Instance.GetService<T>();
        }

    }
    //一些通用的信息
    public static class WebContext
    {
        public static string AdminName
        {
            get
            {
                //获取cookie
                var hasCookie = ServiceLocator.GetService<IHttpContextAccessor>()
                    .HttpContext
                    .Request.Cookies
                    .TryGetValue(ApplicationKeys.User_Cookie_Key, out string encryptValue);
                if (!hasCookie || string.IsNullOrEmpty(encryptValue))
                    return null;
                var adminName = ServiceLocator.GetService<IUserService>().LoginDecrypt(encryptValue, ApplicationKeys.User_Cookie_Encryption_Key);
                return adminName;
            }
        }
        public const string LoginUrl = "/account/login";
    }
    //全局的一些Key值
    public class ApplicationKeys
    {
        public const string User_Cookie_Encryption_Key = "User_Cookie_Encryption_Key";

        public const string User_Cookie_Key = "User_Cookie_Key";
    }
    
    //Startup
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();//用于获取请求上下文
        services.AddTransient<IUserService, UserService>();
        services.AddMvc();
    }
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        //app.UseMvc()..
        //最末的时候赋值
        ServiceLocator.Instance = app.ApplicationServices;
    }

代码说明

  1. 首先定义了一个存放服务的静态对象:ServiceLocator
  2. 在程序启动后将IApplicationBuilder.ApplicationServices赋值给ServiceLocator.Instance,这样就能够在任何地方使用ServiceLocator.Instance获取到注入的服务 (为了更好的获取实例添加了一个T GetService<T>()方法)
  3. 在WebContext中取获取Cookie值:ServiceLocator.GetService<IHttpContextAccessor>().HttpContext.Request.Cookies
  4. 解密获取的cookie得到用户名:ServiceLocator.GetService<IUserService>().LoginDecrypt(encryptValue, ApplicationKeys.User_Cookie_Encryption_Key);
  5. 所以在后台就能使用WebContext.AdminName获取到当前登录用户名,或者根据用户名获取登录信息

总结

  • 自定义特性标记和过滤器之间差开一个IFilterMetadata,换言之:特性标记实现了IFilterMetadata就等于是个过滤器(个人理解)
  • asp.net core中模型绑定使用asp-for
  • asp.net core注入服务: 在 Startup.ConfigureServices方法中注入 services.AddTransient<IUserService, UserService>()
  • asp.net core获取HttpContext对象 参考:ASP.NET Core开发之HttpContext ASP.NET Core中提供了一个IHttpContextAccessor接口,HttpContextAccessor 默认实现了它简化了访问HttpContext。 它必须在程序启动时在IServicesCollection中注册,这样在程序中就能获取到HttpContextAccessor,并用来访问HttpContextservices.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  • asp.net core中表单直接使用form标签,asp-action,asp-controller等指定路由参数即可,并且能够自动生成防伪字段标识,配合ValidateAntiForgeryToken特性标记预防CSRF 代码生成比较图 相关文档地址:https://docs.microsoft.com/zh-cn/aspnet/core/security/anti-request-forgery
  • autofocus属性 可使文本框自动获取焦点

Demo下载地址

探索学习中,若有错误或者不足指出还望园友指出。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏blackheart的专栏

[Asp.Net Core] 1. IIS中的 Asp.Net Core 和 dotnet watch

在基于传统的.NET Framework的Asp.Net Mvc的时候,本地开发环境中可以在IIS中建立一个站点,可以直接把站点的目录指向asp.net mvc...

2989
来自专栏跟着阿笨一起玩NET

winform打开进程与关闭进程

2592
来自专栏听雨堂

页面状态保持机制(编辑中)

Web应用程序中,有很多状态需要在页面的反复回调中能够保持住,还有一些状态需要在页面之间保持。对于状态的保持,是一个值得研究的问题。状态处理不当是页面失效或错误...

2775
来自专栏.NET开发那点事

AServer - 基于Asp.net core Kestrel的超迷你http服务器

  AServer是基于ASP.NET Core Kestrel封装的一个超迷你http服务器。它可以集成进你的Core程序里,用来快速的响应Http请求,而不...

1371
来自专栏码农阿宇

.Net Core从命令行读取配置文件

最近在学习博客园腾飞(jesse)的.Net Core视频教程,收益匪浅,在此作推荐 : http://video.jessetalk.cn/ 言归正传,.Ne...

3054
来自专栏bluesummer

用Token令牌维护微服务之间的通信安全的实现

在微服务架构中,如果忽略服务的安全性,任由接口暴露在网络中,一旦遭受攻击后果是不可想象的、 保护微服务键安全的常见方案有:1.JWT令牌(token) 2.双向...

3657
来自专栏丑胖侠

《Drools7.0.0.Final规则引擎教程》第3章 3.1 Hello World 实例

3.1 Hello World 实例 在上一章中介绍了Drools5x版本中规则引擎使用的实例,很明显在Drools7中KnowledgeBase类已经标注为“...

3376
来自专栏技术小讲堂

ASP.NET AJAX(9)__Profile Service什么是ASP.NET Profile如何使用ASP.NET ProfileProfile ServiceProfile Service预

什么是ASP.NET Profile 可以为每个用户(包括匿名用户)储存信息 通过在Web.config中的配置即可在应用程序中使用 强类型的属性 可以定义属性...

4449
来自专栏hbbliyong

WCF浅尝

1.首先先建立一个WCF服务应用程序 ? 2.再建立一个宿主程序,这里用控制台,添加服务引用,这里会报错: ? 点击页面确定,回到添加服务页面 ? 点击箭头有如...

35910
来自专栏緣來來來

Mac 下使用tree命令列目录

相信很多使用过Linux的用户都用过tree命令,它可以像windows的文件管理器一样清楚明了的显示目录结构。不过有是有并不是系统本身就自带的,如果需要的话,...

1471

扫码关注云+社区

领取腾讯云代金券