zoukankan      html  css  js  c++  java
  • ASP.NET Core 如何用 Cookie 来做身份验证

    前言

    本示例完全是基于 ASP.NET Core 3.0。本文核心是要理解 Claim, ClaimsIdentity, ClaimsPrincipal,读者如果有疑问,可以参考文章 理解ASP.NET Core验证模型(Claim, ClaimsIdentity, ClaimsPrincipal)不得不读的英文博文

    代码

    项目文件 csproj 的配置

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
      <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
      </PropertyGroup>
      <ItemGroup>
      </ItemGroup>
    </Project>

    Program.cs

    注意: ASP.NET Core 3.0 的配置和 v2.2 稍微有一点不同。

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }
    
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

    Startup

    注意:不管是 ConfigureServices 方法,还是 Configure 方法,配置的顺序至关重要,有可能明明配置了 XX,运行时却总是无效。比如笔者实验时,把 app.UseAuthentication(); 写到了 app.UseRouting() 前面,结果导致运行时,标记在 Action 方法上面的 [Authorize] 总是无效,结果发现是注册的顺序搞错了,大家一定要注意这点。

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        public IConfiguration Configuration { get; }
    
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) // Sets the default scheme to cookies
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
                {
                    options.AccessDeniedPath = "/account/denied";
                    options.LoginPath = "/account/login";
                });
    
            services.AddControllersWithViews();
    
            // Example of how to customize a particular instance of cookie options and
            // is able to also use other services.
            // will override CookieAuthenticationOptions, such as LoginPath => "/account/hello"
            //services.AddSingleton<IConfigureOptions<CookieAuthenticationOptions>, ConfigureMyCookie>();
        }
    
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseDeveloperExceptionPage(); // Temp Open
                //app.UseExceptionHandler("/Home/Error");
            }
                
            app.UseStaticFiles();
    
            app.UseRouting();
    
            app.UseAuthentication(); // Remember to put it behind app.UseRouting()
            app.UseAuthorization(); // Remember to put it behind app.UseRouting()
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }

     HomeController

    在需要授权才能访问的 Action 方法上标记  [Authorize]

    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
    
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }
    
        public IActionResult Index()
        {
            return View();
        }
    
        [Authorize]
        public IActionResult MyClaims()
        {
            return View();
        }
    
        public IActionResult Privacy()
        {
            return View();
        }
    }

     _Layout.cshtml

    在这里面,可以通过 @User.Identity.IsAuthenticated 来判断用户是否已经进行了授权,如果已经授权,则显示 “Logout” 链接。

    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="MyClaims">My Claims</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy_@(User.Identity.IsAuthenticated)</a>
    </li>
    @if (User.Identity.IsAuthenticated)
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Logout">Logout</a>
        </li>
    }

    AccountController

    注意:由于之前我们在 Starup 中配置了 CookieAuthenticationOptions 类(Microsoft.AspNetCore.Authentication.Cookies. CookieAuthenticationOptions)的 options.LoginPath = "/account/login"; 这时候如果访问 /home/MyCliams 时,会自动跳转到 /account/login。

    ApplicationUser

        public class ApplicationUser
        {
            public string Email { get; set; }
            public string FullName { get; set; }
        }

    LoginViewModel

        public class LoginViewModel
        {
            public string UserName { get; set; }
    
            public string Password { get; set; }
        }
        public class AccountController : Controller
        {
            [HttpGet]
            public IActionResult Login(string returnUrl = null)
            {
                ViewData["ReturnUrl"] = returnUrl;
                return View();
            }
    
            private async Task<ApplicationUser> AuthenticateUser(string email, string password)
            {
                // For demonstration purposes, authenticate a user
                // with a static email address. Ignore the password.
                // Assume that checking the database takes 500ms
    
                await Task.Delay(500);
    
                //if (email == "maria.rodriguez@contoso.com")
                //{
                    return new ApplicationUser()
                    {
                        Email = "maria.rodriguez@contoso.com",
                        FullName = "Maria Rodriguez"
                    };
                //}
                //else
                //{
                //    return null;
                //}
            }
    
            [HttpPost]
            public async Task<IActionResult> Login(LoginViewModel loginViewModel, string returnUrl = null)
            {
                if (!ModelState.IsValid)
                {
                    return Content("validation fail");
                }
                var user = await AuthenticateUser(loginViewModel.UserName, loginViewModel.Password);
                if (user == null)
                {
                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                    return View();
                }
                ViewData["ReturnUrl"] = returnUrl;
    
                var claims = new List<Claim>
                    {
                        new Claim(ClaimTypes.Name, user.Email),
                        new Claim("FullName", user.FullName),
                        new Claim(ClaimTypes.Role, "Administrator"),
                    };
    
                var claimsIdentity = new ClaimsIdentity(
                    claims, CookieAuthenticationDefaults.AuthenticationScheme);
    
                var authProperties = new AuthenticationProperties
                {
                    //AllowRefresh = <bool>,
                    // Refreshing the authentication session should be allowed.
    
                    //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10),
                    // The time at which the authentication ticket expires. A 
                    // value set here overrides the ExpireTimeSpan option of 
                    // CookieAuthenticationOptions set with AddCookie.
    
                    //IsPersistent = true,
                    // Whether the authentication session is persisted across 
                    // multiple requests. When used with cookies, controls
                    // whether the cookie's lifetime is absolute (matching the
                    // lifetime of the authentication ticket) or session-based.
    
                    //IssuedUtc = <DateTimeOffset>,
                    // The time at which the authentication ticket was issued.
    
                    //RedirectUri = <string>
                    // The full path or absolute URI to be used as an http 
                    // redirect response value.
                };
    
                await HttpContext.SignInAsync(
                    CookieAuthenticationDefaults.AuthenticationScheme,
                    new ClaimsPrincipal(claimsIdentity),
                    authProperties);
    
                if (Url.IsLocalUrl(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    return Redirect("/");
                }
            }
    
            public IActionResult AccessDenied(string returnUrl = null)
            {
                return View();
            }
    
            public async Task<IActionResult> Logout()
            {
                #region snippet1
                await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
                #endregion
    
                return Redirect("/");
            }
        }

    上面的代码即包含“登录”方法,又包含登出方法。

    await HttpContext.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,
        new ClaimsPrincipal(claimsIdentity),
        authProperties);

    关于 Claim, ClaimsIdentity, ClaimsPrincipal,读者如果有疑问,可以参考文章 理解ASP.NET Core验证模型(Claim, ClaimsIdentity, ClaimsPrincipal)不得不读的英文博文

    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

     MyClaims.cshtml

    @using Microsoft.AspNetCore.Authentication
    
    <h2>HttpContext.User.Claims</h2>
    
    <dl>
        @foreach (var claim in User.Claims)
        {
            <dt>@claim.Type</dt>
            <dd>@claim.Value</dd>
        }
    </dl>
    
    <h2>AuthenticationProperties</h2>
    
    <dl>
        @{
            var taskAuth = await Context.AuthenticateAsync();
        }
        @if(taskAuth != null && taskAuth.Properties != null && taskAuth.Properties.Items != null)
        {
            @foreach (var prop in taskAuth.Properties.Items)
            {
                <dt>@prop.Key</dt>
                <dd>@prop.Value</dd>
            }
        }
        else
        {
            <dt>no data.</dt>
        }
    </dl>

     运行截图

    1. 没有登录的情况下

    2. 登录界面

    3. 登录成功

    谢谢浏览!

  • 相关阅读:
    漫谈五种IO模型
    jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)
    Intellij IDEA 插件开发秘籍
    二进制
    java程序员必知的 8大排序
    Redis常见问题
    BitMap位图
    编程思想
    Final修饰的字段是否可以通过反射设置值
    ORACLE 11g ORA-20000: Unable to analyze TABLE "AA"."CMP3$87651", insufficient privileges or does not exist
  • 原文地址:https://www.cnblogs.com/Music/p/How-to-use-cookies-for-authentication-in-asp-net-core-3.html
Copyright © 2011-2022 走看看