來吧學學.Net Core之登入認證與跨域資源使用

張龍豪發表於2017-06-27

序言

學習core登入認證與跨域資源共享是越不過的砍,所以我在學習中同樣也遇到啦這兩個問題,今天我們就用示例來演示下使用下這2個技術點吧.

本篇主要內容如下:

1、展示一個登入認證的簡單示例

2、跨域資源訪問

3、跨域獲取登入認證的使用者資訊

.Net Core使用身份認證(Authentication,Identity)製作登入認證功能

首先我們實現登入這個功能,程式碼如下

    [Authorize]
    public class AccountController : Controller
    {
        [HttpGet]
        [AllowAnonymous]
        public IActionResult Login(string returnUrl = null)
        {
            ViewData["ReturnUrl"] = returnUrl;
            if (this.User.Identity.IsAuthenticated)
            {
                return RedirectPermanent(returnUrl);
            }
            return View();
        }
        [HttpPost]
        [AllowAnonymous]
        public async Task<IActionResult> Login(string userName, string password,string returnUrl=null)
        {
            ViewData["ReturnUrl"] = returnUrl;          
            if (!string.IsNullOrEmpty(userName) && userName == password)
            {
                var claims = new List<Claim>(){
                              new Claim(ClaimTypes.Name,userName),new Claim("password",password),new Claim("realname","張龍豪")
                           };
                //init the identity instances 
                var userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Customer"));
                //signin 
                await HttpContext.Authentication.SignInAsync("CookieAuth", userPrincipal, new AuthenticationProperties
                {
                    ExpiresUtc = DateTime.UtcNow.AddMinutes(20),
                    IsPersistent = false,
                    AllowRefresh = false
                });
                return RedirectPermanent(returnUrl);
            }
            else
            {
                ViewBag.ErrMsg = "UserName or Password is invalid";
                return View();
            }
        }

前臺程式碼如下

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Login</title>
</head>
<body>
    <form asp-controller="Account" asp-action="Login" method="post" class="form-horizontal" asp-route-returnurl="@ViewData["ReturnUrl"]" role="form">
        <div class="form-group">
            <label class="col-md-2 control-label">UserName</label>
            <div class="col-md-10">
                <input type="text" name="username" />
            </div>
        </div>
        <div class="form-group">
            <label class="col-md-2 control-label">Password</label>
            <div class="col-md-10">
                <input type="password" name="password" />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <button type="submit" class="btn btn-default">Log in</button>
            </div>
        </div>
    </form>
</body>
</html>

在Startup檔案的Configure方法中加入下面程式碼

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {          
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationScheme = "CookieAuth",   //認證方案:這是一個已知中介軟體的值,當有多個例項的中介軟體如果你想限制授權到一個例項時這個選項將會起作用。
                LoginPath = new PathString("/Account/Login"), //登入路徑:這是當使用者試圖訪問資源但未經過身份驗證時,程式將會將請求重定向到這個相對路徑。
                AccessDeniedPath = new PathString("/Account/Forbidden"),  //禁止訪問路徑:當使用者試圖訪問資源時,但未通過該資源的任何授權策略,請求將被重定向到這個相對路徑。
                AutomaticAuthenticate = true,  //自動認證:這個標誌表明中介軟體應該會在每個請求上進行驗證和重建他建立的序列化主體。                
                AutomaticChallenge = true,  //自動挑戰:這個標誌標明當中介軟體認證失敗時應該重定向瀏覽器到登入路徑或者禁止訪問路徑。
                SlidingExpiration = true,  //Cookie可以分為永久性的和臨時性的。 臨時性的是指只在當前瀏覽器程式裡有效,瀏覽器一旦關閉就失效(被瀏覽器刪除)。 永久性的是指Cookie指定了一個過期時間,在這個時間到達之前,此cookie一直有效(瀏覽器一直記錄著此cookie的存在)。 slidingExpriation的作用是,指示瀏覽器把cookie作為永久性cookie儲存,但是會自動更改過期時間,以使使用者不會在登入後並一直活動,但是一段時間後卻自動登出。也就是說,你10點登入了,伺服器端設定的TimeOut為30分鐘,如果slidingExpriation為false,那麼10:30以後,你就必須重新登入。如果為true的話,你10:16分時開啟了一個新頁面,伺服器就會通知瀏覽器,把過期時間修改為10:46。 更詳細的說明還是參考MSDN的文件。
                CookieHttpOnly = false  //預設為true
            });

好啦,你可以看到有[Authorize]屬性的方法或者控制器都需要登入才能訪問,如果沒有登入是不允許訪問的.

接下來你可能需要獲取當前登入使用者的使用者資訊,程式碼如下:

        [HttpPost]
        public string GetCurrUserRealname()
        {
            var s = this.User.Identities.First(u => u.IsAuthenticated).FindFirst("realname").Value;
            var ss = this.User.Identity.Name;
            return ss + ":" + s;
        }
 $.post("/Account/GetCurrUserRealname", null, function (data) { $("#content").html(data); });

ok,這樣就能獲取到當前登入的使用者資訊

那如何退出呢?程式碼如下:

        public async Task<JsonResult> Logout()
        {
            await HttpContext.Authentication.SignOutAsync("CookieAuth");
            return Json(new { data = "驗證方案:CookieAuth退出成功" });
        }

這樣看來完整的登入驗證就完成啦,但是目前位置,我的程式碼都還簡單的要命,只能初學者拿來入手,具體還有很多東西可以擴充套件.我們需要自己思考學習.

.Net Core跨域資源訪問

那這個跨域的環境呢,需要我們自己搞一下.怎麼搞,如下

本地測試前期準備

1.首先我們搞兩個core的站點

 

2.本地host配置兩個域名,並在專案中做如下設定

hosts如下:

網站的launchSettings.json檔案中配置專案CoreCorsATest為 "applicationUrl": "http://b.local.com:63455/",  專案AuthentiactionTest為 "applicationUrl": "http://a.local.com:50307/".

3. 實驗約定:

我們在專案AuthentiactionTest中寫介面,專案CoreCorsATest中呼叫AuthentiactionTest中的介面.

不做任何處理寫介面跨域呼叫

AuthentiactionTest中寫下如下介面

 public class HomeController : Controller
    {
        public string GetName()
        {
            return "張龍豪";
        }

CoreCorsATest中如下呼叫

$.post("http://a.local.com:50307/Home/GetName", null, function (data) { $("#content").html(data); });

結果如下:介面呼叫成功,但是跨域資源不允許使用

解決問題

設定跨域的域名

 public void ConfigureServices(IServiceCollection services)
        {
            //services.AddAuthorization();
            // Add framework services.
            services.AddMvc();
            services.AddCors(options => options.AddPolicy("AllowSameDomain", builder => builder.WithOrigins("http://a.local.com:50307", "http://b.local.com:63455")));
        }

下面的兩種呼叫方式

  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
           app.UseCors("AllowSameDomain");
 public class HomeController : Controller
    {
        [EnableCors("AllowSameDomain")]
        public string GetName()
        {
            return "張龍豪";
        }

.Net Core跨域訪問需要登入認證的資源

這個問題就是上面跨域訪問的資源如果出現 [Authorize]特性,或者是訪問當前使用者的登入資訊,用剛才的方法是不行的.

登入使用,上述的登入功能,介面如下

        [HttpPost]
        public string GetCurrUserRealname()
        {
            var s = this.User.Identities.First(u => u.IsAuthenticated).FindFirst("realname").Value;
            var ss = this.User.Identity.Name;
            return ss + ":" + s;
        }

那在b.local.com 這個域名下怎麼訪問才是有效的呢?

需要下面兩部操作

1.設定介面服務專案配置,如下操作

services.AddCors(options => options.AddPolicy("AllowSameDomain", builder => builder.WithOrigins("http://a.local.com:50307", "http://b.local.com:63455").AllowCredentials()));

2.ajax訪問介面時

 $.ajax({
            type: 'POST',
            url: "http://a.local.com:50307/Account/GetCurrUserRealname",
            data: null,
            dataType: "json",
            xhrFields: {
                withCredentials: true
            },
            success: function (result) {
                $("#message").html(result);
            }
        });

ok,這樣就可以訪問到當前登入使用者的資訊啦

總結

本篇呢,寫的都是用例,理論原理,沒有涉及,也有一些其他常用額擴充套件點,都沒有涉及到.

這裡我只是把一些的點,貼出來,希望對想入手core的同學有所幫助.如有志同道合者,歡迎加左上方群,一起學習進步.

相關文章