blazor SignInAsync實現登錄


前言

在MVC中我們經常使用內置的Identity來實現登錄,簡單快捷。當然,還有其他方式來實現,但是在blazor中使用 SignInAsync會出現這樣的錯誤 "The response headers cannot be modified because the response has already started"。

我通過依賴注入IHttpContextAccessor _httpContextAccessor,來獲取HttpContext調用SignInAsync方法。blazor是SignaIR 長輪詢來實現的,所以會出現這樣的錯誤。我們需要創建一個新的請求來實現。

實現

ASP.NET Core 項目是可以同時托管多種不同的程序的。例如,在一個項目能運行Webapi和Blazor(注意,我指的並不是在一個解決方案),我們需要創建一個控制器,添加登錄方法。

//AccountController.cs
public class AccountController :ControllerBase
    {
        private readonly IDbContextFactory<BlogContext> _dbFactory;
        private readonly IDataProtectionProvider _dataProtectionProvider;

        public AccountController(IDataProtectionProvider dataProtectionProvider, IDbContextFactory<BlogContext> dbFactory)
        {
            _dbFactory = dbFactory;
            _dataProtectionProvider = dataProtectionProvider;
        }

        /// <summary>
        /// 后端登錄
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("Login")]
        //[AuthorizationVerify]
        [Authorize(Policy = "AtLeast21")]
        public async Task<IActionResult> Login(string token)
        {
            var dataProtect = _dataProtectionProvider.CreateProtector("Login");
            var data = dataProtect.Unprotect(token);
            var parts = data.Split('|');

            using var context = _dbFactory.CreateDbContext();
            var user = await context.Admin.FirstOrDefaultAsync(x => !x.IsDelete && x.Uno.Equals(parts[0]) && x.PassWord.Equals(parts[1]));

            if (user != null)
            {
                #region 用戶信息憑證
                AuthenticationProperties props = null;

                var claims = new List<Claim>() {
                    new Claim(ClaimTypes.Sid, user.Uno),
                    new Claim(ClaimTypes.Name,user.UserName),
                    new Claim(ClaimTypes.Uri, user.ImageUrl),
                    };

                props = new AuthenticationProperties
                {
                    IsPersistent = true,
                    ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1))
                };

                await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
                new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme)),
                props);
                #endregion

                return Redirect("/Admin/index");
            }
            else 
            {
                return Redirect($"/Login/{true}");
            }
        }
    }

上面,我們創建了一個控制器,添加了登錄驗證方法。但想要同時運行Webapi和Blazor,還需要對Startup.cs文件 Configure方法終結點進行修改。

// Startup.cs
app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
                endpoints.MapControllers();  
                // 新添加的控制器終結點
                // 項目會按照終結點的順序來進行訪問
                // 先走上面的Blazor,如果找不對應的路由信息
                // 會走到webapi的控制器路由來查找
            });  

接下來,就是Login.Razor組件的部分了。這里我們需要通過加密處理賬號和密碼,通過_navigationManager來實現調用。這里不能使用httpclient的方式,應該是請求會被判斷為服務器發出,在瀏覽器內的NetWork中沒有記錄。(只是猜測,也可能是長輪詢的問題)

//Login.Razor.cs

//賬號密碼加密處理
//需要注入IDataProtectionProvider _dataProtectionProvider
var dataProtect = _dataProtectionProvider.CreateProtector("Login");
var input = dataProtect.Protect($"{model.Username}|{model.Password}");

//需要在組件中注入NavigationManager _navigationManager
_navigationManager.NavigateTo("/api/Account/Login?token=" + input, true);

控制器中的Login方法通過Redirect重定向回來,或去要訪問的頁面就可以了。

這樣就成功實現登錄功能了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM