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认证介绍

1412316-20191001014457039-1792976912.jpg

任务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

1412316-20191001014509218-1684426084.jpg

实际情况不应该直接让用户访问到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

1412316-20191001014521177-419352918.jpg

在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 认证授权介绍

1412316-20191001014532906-1908588066.jpg

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

1412316-20191001014547047-2082649638.jpg

任务36:应用Jwtbearer Authentication

dotnet new webapi --name JwtAuthSample
dotnet watch run

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

1412316-20191002172004962-879288043.png

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,未授权

1412316-20191002172016580-241379177.png

任务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

1412316-20191002172310137-1650066765.jpg

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

1412316-20191002172339742-33389572.jpg

1412316-20191002172058861-1172042339.jpg

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

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

1412316-20191002172109311-1481864615.jpg

任务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,禁止访问

1412316-20191004002651315-1627239655.png

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

1412316-20191004002700381-76840959.jpg

任务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) 。

转载于:https://www.cnblogs.com/MingsonZheng/p/11614686.html

<think>好的,我现在需要帮助用户了解C#软件开发教程,从入门到精通。首先,用户提到了参考站内引用中的菜鸟教程笔记,涵盖了C#概述、开发环境、程序结构、基本语法、数据类型、类型转换、变量、常量运算符。我需要基于这些内容,按照用户的系统级指令来组织回答,包括正确使用LaTeX格式的中文回答,生成相关问题,并引用给定的参考资料。 首先,我要确保回答的结构清晰,分步骤讲解。用户需要从入门到精通,所以应该分阶段:入门阶段、进阶阶段精通阶段。每个阶段需要列出关键知识点,并给出对应的示例代码,同时注意代码的正确性相关注释。 接下来,检查是否需要使用LaTeX。根据指令,行内数学表达式用$...$,独立公式用$$...$$。但在C#教程中,可能数学公式较少,不过如果有涉及算法或计算的地方,比如复杂度分析,可能需要用到。例如,在讲解算法复杂度时,可以提到快速排序的平均时间复杂度是$O(n \log n)$,最坏情况是$O(n^2)$,这样既符合LaTeX要求,又引用了相关知识。 然后,生成相关问题。根据示例,问题应该围绕C#学习的深入内容、优化方法、应用场景等方面。比如,如何理解C#的垃圾回收机制,如何进行性能优化,C#在游戏开发中的应用等。 还需要注意引用资料。用户提供的引用[1]是菜鸟教程的中篇内容,可能没有涵盖所有内容,但回答中提到的部分如程序结构、语法等可以引用[^1]。但需要确认引用内容是否在提供的参考资料中。例如,在介绍数据类型时,可以引用,因为参考资料中提到了数据类型部分。 另外,代码块需要用正确的语法高亮,比如注明语言是C#,并确保代码正确。例如,入门阶段的Hello World程序,进阶阶段的类对象示例,精通阶段的LINQ查询等。 现在需要组织内容: 1. 入门阶段:安装开发环境(Visual Studio)、基本语法(Hello World)、数据类型、变量常量、运算符。 2. 进阶阶段:面向对象编程(类、继承、多态)、异常处理、集合、文件操作。 3. 精通阶段:高级特性(LINQ、异步编程)、框架应用(ASP.NET Core)、性能优化、设计模式。 4. 学习资源推荐:官方文档、书籍、在线课程。 5. 相关问题:内管理、性能优化、跨平台开发、游戏开发应用、.NET 5/6新特性。 检查每个部分是否有需要补充的LaTeX公式,例如在时间复杂度或算法部分。例如,在讲解快速排序时可能会提到时间复杂度,但用户的问题是关于C#,所以可能较少,如果有涉及算法部分,可以适当加入。 最后,确保所有引用正确,例如在提到数据类型、程序结构时添加。同时,生成的三个相关问题需要C#相关,并覆盖不同层次的问题。</think>### C# 软件开发教程:从入门到精通 #### **一、入门阶段** 1. **开发环境搭建** - 安装 Visual Studio(推荐最新版本),选择“.NET 桌面开发”工作负载[^1]。 - 创建第一个控制台项目: ```csharp using System; class Program { static void Main() { Console.WriteLine("Hello, C#!"); // 输出语句 } } ``` 2. **基本语法程序结构** - 程序结构:命名空间(`namespace`)、类(`class`)、方法(`Main`)。 - 数据类型:类型(如 `int`, `double`)引用类型(如 `string`, `object`)。 - 变量常量: ```csharp int number = 10; // 变量 const float PI = 3.14f; // 常量 ``` 3. **运算符控制流** - 算术运算符:`+`, `-`, `*`, `/` - 条件语句:`if-else`, `switch` - 循环语句:`for`, `while` ```csharp for (int i = 0; i < 5; i++) { Console.WriteLine($"当前:{i}"); } ``` --- #### **二、进阶阶段** 1. **面向对象编程(OOP)** - **类对象**: ```csharp public class Person { public string Name { get; set; } // 属性 public void Speak() { // 方法 Console.WriteLine($"我是{Name}"); } } ``` - **继承多态**: ```csharp public class Student : Person { public string School { get; set; } public override void Speak() { Console.WriteLine($"我是学生{Name},来自{School}"); } } ``` 2. **异常处理文件操作** - `try-catch` 捕获异常: ```csharp try { int result = 10 / int.Parse("0"); } catch (DivideByZeroException ex) { Console.WriteLine("除数不能为0!"); } ``` - 文件读写: ```csharp string text = File.ReadAllText("test.txt"); File.WriteAllText("output.txt", text.ToUpper()); ``` --- #### **三、精通阶段** 1. **高级特性** - **LINQ(语言集成查询)**: ```csharp var numbers = new List<int> { 1, 2, 3, 4, 5 }; var evenNumbers = from num in numbers where num % 2 == 0 select num; ``` - **异步编程(async/await)**: ```csharp public async Task DownloadDataAsync() { HttpClient client = new HttpClient(); string data = await client.GetStringAsync("https://example.com"); Console.WriteLine(data); } ``` 2. **框架性能优化** - **ASP.NET Core 开发**:构建 Web API 或 MVC 应用。 - **性能调优**:使用 `Stopwatch` 分析代码执行时间,减少内分配。 --- #### **四、学习资源推荐** 1. **官方文档**:[Microsoft Learn C# 教程](https://learn.microsoft.com/zh-cn/dotnet/csharp/) 2. **书籍**:《C# 入门经典》《CLR via C#》 3. **实战项目**:从控制台工具到 Unity 游戏开发。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值