登錄流程圖
示例預覽
構建步驟
當然,你也可以直接之前前往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;
}
代碼說明
- 首先定義了一個存放服務的靜態對象:
ServiceLocator
- 在程序啟動后將
IApplicationBuilder.ApplicationServices
賦值給ServiceLocator.Instance
,這樣就能夠在任何地方使用ServiceLocator.Instance
獲取到注入的服務
(為了更好的獲取實例添加了一個T GetService<T>()
方法) - 在WebContext中取獲取Cookie值:
ServiceLocator.GetService<IHttpContextAccessor>().HttpContext.Request.Cookies
- 解密獲取的cookie得到用戶名:
ServiceLocator.GetService<IUserService>().LoginDecrypt(encryptValue, ApplicationKeys.User_Cookie_Encryption_Key);
- 所以在后台就能使用
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
,並用來訪問HttpContext
。
services.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下載地址
- 點擊下載Demo
- Coding倉庫地址克隆代碼:
git clone https://git.coding.net/yimocoding/WeDemo.git -b LoginDemo LoginDemo
探索學習中,若有錯誤或者不足指出還望園友指出。