zoukankan      html  css  js  c++  java
  • ASP.NET Core快速入门(第5章:认证与授权)--学习笔记

    课程链接:http://video.jessetalk.cn/course/explore

    良心课程,大家一起来学习哈!

    任务31:课时介绍

    • 1.Cookie-based认证与授权
    • 2.Cookie-based认证实现
    • 3.Jwt认证与授权介绍
    • 4.Jwt认证与授权实现
    • 5.Jwt认证与授权
    • 6.Role based授权
    • 7.Claims-based授权

    任务32:Cookie-based认证介绍

    任务34:Cookie-based认证实现

    dotnet new mvc --name MvcCookieAuthSample
    

    在Controllers文件夹新增AdminController.cs

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using MvcCookieAuthSample.Models;
    
    namespace MvcCookieAuthSample.Controllers
    {
        public class AdminController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
        }
    }
    
    

    在Views文件夹新增Admin文件夹,在Admin文件夹新增Index.cshtml

    @{
        ViewData["Title"] = "Admin";
    }
    <h2>@ViewData["Title"]</h2>
    
    <p>Admin Page</p>
    
    

    启动项目,浏览器访问https://localhost:5001/Admin

    实际情况不应该直接让用户访问到Admin页面,所以应当跳转到登陆界面

    AdminController.cs

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using MvcCookieAuthSample.Models;
    // 添加引用
    using Microsoft.AspNetCore.Authorization;
    
    namespace MvcCookieAuthSample.Controllers
    {
        public class AdminController : Controller
        {
            [Authorize]
            public IActionResult Index()
            {
                return View();
            }
        }
    }
    
    

    startup.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.HttpsPolicy;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    // 添加引用
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Authentication.Cookies;
    
    namespace MvcCookieAuthSample
    {
        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.Configure<CookiePolicyOptions>(options =>
                {
                    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                    options.CheckConsentNeeded = context => true;
                    options.MinimumSameSitePolicy = SameSiteMode.None;
                });
    
                // Addmvc之前AddAuthentication,AddCookie
                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie();
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                    app.UseHsts();
                }
    
                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseCookiePolicy();
    
                // UseMvc之前UseAuthentication,添加Middleware
                app.UseAuthentication();
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
        }
    }
    
    

    再次访问https://localhost:5001/Admin,跳转到登陆界面https://localhost:5001/Account/Login?ReturnUrl=%2FAdmin

    在Controllers文件夹新增AccountController.cs

    
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using MvcCookieAuthSample.Models;
    // 添加引用
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authentication.Cookies;
    using System.Security.Claims;
    
    namespace MvcCookieAuthSample.Controllers
    {
        [Authorize]
        public class AccountController : Controller
        {
            public IActionResult MakeLogin()
            {
                var claims = new List<Claim>()
                {
                    new Claim(ClaimTypes.Name,"Mingson"),
                    new Claim(ClaimTypes.Role,"admin")
                };
    
                var claimIdentity = new ClaimsIdentity(claims,CookieAuthenticationDefaults.AuthenticationScheme);
    
                HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,new ClaimsPrincipal(claimIdentity));
                
                return Ok();
            }
    
            public IActionResult Logout()
            {
                HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
                
                return Ok();
            }
        }
    }
    
    

    启动项目

    登出:localhost:5000/account/logout
    访问admin:localhost:5000/admin,跳转到account/login
    登陆:localhost:5000/account/makelogin
    再次访问admin:localhost:5000/admin,登陆成功访问admin

    任务35:JWT 认证授权介绍

    可在官网解密:https://jwt.io

    任务36:应用Jwtbearer Authentication

    dotnet new webapi --name JwtAuthSample
    dotnet watch run
    

    打开postman调用
    http://localhost:5000/api/values

    ValuesController.cs

    // 添加引用
    using Microsoft.AspNetCore.Authorization;
    
        // 添加特性
        [Authorize]
        [Route("api/[controller]")]
        [ApiController]
        public class ValuesController : ControllerBase
    

    新增一个Models文件夹,在文件夹中新增JwtSettings.cs

    namespace JwtAuthSample
    {
        public class JwtSettings
        {
            // token颁发者
            public string Issure{get;set;}
            // token使用的客户端
            public string Audience{get;set;}
            // 加密Key
            public string SecretKey="hellokey";
        }
    }
    

    appsettings.json

    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*",
      "JwtSettings":{
        "Audience":"http://localhost:5000",
        "Issuer":"http://localhost:5000",
        "SecretKey":"Hello-key"
      }
    }
    

    Startup.cs

    // 添加引用
    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.IdentityModel.Tokens;
    using System.Text;
    
                // 添加在services.AddMvc()之前
                services.Configure<JwtSettings>(Configuration);
                var JwtSettings = new JwtSettings();
                Configuration.Bind("JwtSettings",JwtSettings);
                // 认证MiddleWare配置
                services.AddAuthentication(options=>{
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                // Jwt配置
                .AddJwtBearer(o=>{
                    o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters{
                        ValidIssuer = JwtSettings.Issure,
                        ValidAudience = JwtSettings.Audience,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSettings.SecretKey))// 对称加密
                    };
                });
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    
                app.UseHttpsRedirection();
                // 添加在app.UseMvc()之前
                app.UseAuthentication();
    
    dotnet watch run
    

    postman调用
    http://localhost:5000/api/values
    返回401,未授权

    任务37:生成 JWT Token

    新建文件夹ViewModels,在文件夹中新建LoginViewModel.cs

    using System.ComponentModel.DataAnnotations;
    
    namespace JwtAuthSample
    {
        public class LoginViewModel
        {
            [Required]
            public string User{get;set;}
            [Required]
            public string Password{get;set;}
        }
    }
    

    AuthorizeController.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    // 添加引用
    using System.Security.Claims;
    using Microsoft.IdentityModel.Tokens;
    using Microsoft.Extensions.Options;
    using System.Text;
    using System.IdentityModel.Tokens.Jwt;
    
    namespace JwtAuthSample.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class AuthorizeController : ControllerBase
        {
            private JwtSettings _jwtSettings;
    
            public AuthorizeController(IOptions<JwtSettings> _jwtSettingsAccesser)
            {
                _jwtSettings = _jwtSettingsAccesser.Value;
            }
    
            public IActionResult Token(LoginViewModel viewModel)
            {
                if (ModelState.IsValid)
                {
                    if (!(viewModel.User == "mingson" && viewModel.Password == "123456"))
                    {
                        return BadRequest();
                    }
    
                    var claims = new Claim[]
                    {
                        new Claim(ClaimTypes.Name, "mingson"),
                        new Claim(ClaimTypes.Role, "admin")
                    };
    
                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));// 对称加密算法
                    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    
                    // VSCode安装扩展NuGet Package Manager
                    // ctrl + shift + p
                    // NuGet Package Manager:Add Pcakage
                    // Microsoft.AspNetCore.Authentication.JwtBearer
                    // 需要FQ才能添加
                    // 2.0.0
                    // 安装到csproj
                    // 安装成功后csproj中出现<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.0.0" />
                    // dotnet restore
    
                    var token = new JwtSecurityToken(
                        _jwtSettings.Issure,
                        _jwtSettings.Audience,
                        claims,
                        DateTime.Now,
                        DateTime.Now.AddMinutes(30),
                        creds);
    
                    return Ok(new {token = new JwtSecurityTokenHandler().WriteToken(token)});
                }
    
                return BadRequest();
            }
        }
    }
    
    

    Startup.cs

                // 添加在services.AddMvc()之前
                //services.Configure<JwtSettings>(Configuration);// 获取不到JwtSettings配置
                services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings"));// 获取appsettings.json中的配置
    

    appsettings.json

    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*",
      "JwtSettings":{
        "Audience":"http://localhost:5000",
        "Issuer":"http://localhost:5000",
        "SecretKey长度必须大于128bit=16字符":"",
        "SecretKey":"Hello-key.jessetalk"
      }
    }
    
    dotnet watch run
    

    postman调用
    http://localhost:5000/Authorize/Token
    返回Token

    加上token调用
    http://localhost:5000/api/values

    token可在官网解密:https://jwt.io

    输入正确的SecretKey:Hello-key.jessetalk

    任务38:JWT 设计解析及定制

    新建文件MyTokenValidator.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Logging;
    // 添加引用
    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using System.Security.Claims;
    using Microsoft.IdentityModel.Tokens;
    
    namespace JwtAuthSample
    {
        public class MyTokenValidator : ISecurityTokenValidator
        {
            bool ISecurityTokenValidator.CanValidateToken => true;
    
            int ISecurityTokenValidator.MaximumTokenSizeInBytes { get;set; }
    
            bool ISecurityTokenValidator.CanReadToken(string securityToken)
            {
                return true;
            }
    
            ClaimsPrincipal ISecurityTokenValidator.ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
            {
                validatedToken = null;
                var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
    
                if (securityToken == "abcdefg")
                {
                    identity.AddClaim(new Claim("name", "mingson"));
                    identity.AddClaim(new Claim("SuperAdminOnly", "true"));
                    identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, "user"));
                }
    
                var principal = new ClaimsPrincipal(identity);
    
                return principal;
            }
        }
    }
    
    

    Startup.cs

                // 认证MiddleWare配置
                services.AddAuthentication(options=>{
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                // Jwt配置
                .AddJwtBearer(o=>{
                    // o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters{
                    //     ValidIssuer = JwtSettings.Issure,
                    //     ValidAudience = JwtSettings.Audience,
                    //     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSettings.SecretKey))// 对称加密
                    // };
    
                    // 修改token来源
                    o.SecurityTokenValidators.Clear();// 一个包含验证的数组,先清除
                    o.SecurityTokenValidators.Add(new MyTokenValidator());
    
                    // 修改token验证方式
                    o.Events = new JwtBearerEvents(){
                      OnMessageReceived = context => {
                          var token = context.Request.Headers["mytoken"];
                          context.Token = token.FirstOrDefault();
                          return Task.CompletedTask;
                      }  
                    };
                });
                
                services.AddAuthorization(Options=>{
                    Options.AddPolicy("SuperAdminOnly", policy => policy.RequireClaim("SuperAdminOnly"));
                });
    

    AuthorizeController.cs

                    // var claims = new Claim[]
                    // {
                    //     new Claim(ClaimTypes.Name, "mingson"),
                    //     new Claim(ClaimTypes.Role, "admin")
                    // };
                    var claims = new Claim[]
                    {
                        new Claim(ClaimTypes.Name, "mingson"),
                        new Claim(ClaimTypes.Role, "user"),
                        new Claim("SuperAdminOnly", "true")
                    };
    

    ValuesController.cs

    // [Authorize]// 添加标签
        [Authorize(Policy="SuperAdminOnly")]
    
    dotnet run
    

    输入一个错误的mytoken,返回403 Forbidden,禁止访问

    输入一个正确的mytoken,返回200 OK

    任务39:Role以及Claims授权

    Role授权

    AuthorizeController.cs

                    var claims = new Claim[]
                    {
                        new Claim(ClaimTypes.Name, "mingson"),
                        new Claim(ClaimTypes.Role, "admin")
                    };
    

    ValuesController.cs

        [Authorize(Roles="user")]
    
    dotnet run
    

    带着token访问,返回403 Forbidden,禁止访问

    AuthorizeController.cs修改为user,可访问

                    var claims = new Claim[]
                    {
                        new Claim(ClaimTypes.Name, "mingson"),
                        new Claim(ClaimTypes.Role, "user")
                    };
    

    Claims授权

    Startup.cs

                // 认证MiddleWare配置
                services.AddAuthentication(options=>{
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                // Jwt配置
                .AddJwtBearer(o=>{
                    o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters{
                        ValidIssuer = JwtSettings.Issure,
                        ValidAudience = JwtSettings.Audience,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSettings.SecretKey))// 对称加密
                    };
                });
    
                services.AddAuthorization(Options=>{
                    Options.AddPolicy("SuperAdminOnly", policy => policy.RequireClaim("SuperAdminOnly"));
                });
    

    ValuesController.cs

        [Authorize(Policy="SuperAdminOnly")]
    

    AuthorizeController.cs

                    var claims = new Claim[]
                    {
                        new Claim(ClaimTypes.Name, "mingson"),
                        new Claim(ClaimTypes.Role, "user"),
                        new Claim("SuperAdminOnly", "true")
                    };
    
    dotnet run
    

    带着token访问,返回200 Ok

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

    欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

    如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

  • 相关阅读:
    Mac上搭建Web服务器
    从零开始学ios开发(三):第一个有交互的app
    从零开始学ios开发(二):Hello World!
    C#核心语法
    WP8的新功能-通过一个程序来启动另一个程序
    .NET Web开发技术简单整理
    windows phone 下拉刷新
    使用X.509数字证书加密解密实务(一)-- 证书的获得和管理
    使用X.509数字证书加密解密实务(三)-- 使用RSA证书结合对称加密技术加密长数据
    使用X.509数字证书加密解密实务(二)-- 使用RSA证书加密敏感数据
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/11614686.html
Copyright © 2011-2022 走看看