Core papers - Preliminary Core authentication, authorization mechanisms

Reproduced in: https://www.cnblogs.com/liumengchen-boke/p/8243393.html

table of Contents

1, Cookie-based authentication implementation

2, Jwt Token authentication and authorization

3, the Identity Authentication  + EF  certification

Cookie-based authentication implementation

  cookie authentication mode as shown below, when we visit a Web page (Admin / Index) time, this time the system will check whether you have permission, if you do not have permission, I will present Url redirected to the login page (/ Account / Login) , after the successful landing, the system will return a cookie stored in your browser, then re-took the cookie to re-visit the page you want to access the very beginning (Admin / Index). As shown below.

We .net core, but also based on a set of cookie-basic authentication method.

  First, create a Core 2.0 of MVC project, add two controllers AdminController on behalf of the resources we have to be certified to access the rear, AccountController , simulated landing. In AccountController in

 

Copy the code
1     [Authorize]
2     public class AdminController : Controller
3     {
4         public IActionResult Index()
5         {
6             return View();
7         }
8     }
Copy the code

 

Copy the code
 1     public class AccountController : Controller
 2     {
 3         public async Task<IActionResult> MakeLogin()
 4         {
 5             var claims = new List<Claim>
 6             {
 7                 new Claim(ClaimTypes.Name,"lmc"),
 8                 new Claim(ClaimTypes.Role, "admin")
 9             };
10             var claimsIdentity = new ClaimsIdentity(
11                 claims,
12                 CookieAuthenticationDefaults.AuthenticationScheme
13                 );
14             await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
15                 new ClaimsPrincipal(claimsIdentity),
{New new AuthenticationProperties 16
17 IsPersistent = true, // cookie set the expiration time lasting 
18 ExpiresUtc = DateTime.UtcNow.AddSeconds (20) // set the expiration 20 seconds 
. 19}); 
20 is return Ok (); 
21 is} 
22 is the async public the Task <IActionResult> Zimbabwe Logout () 
23 is { 
24 HttpContext.SignOutAsync the await ( 
25 CookieAuthenticationDefaults.AuthenticationScheme); 
26 is return Ok (); 
27} 
28}
Copy the code

Then we configure Startup, the authentication service is added to the DI container && certified reference middleware.

Copy the code
Public void ConfigureServices. 1 (IServiceCollection Services) 
 2 { 
 . 3 services.AddAuthentication (CookieAuthenticationDefaults.AuthenticationScheme) 
 . 4 .AddCookie (config => 
 . 5 { 
 . 6 config.LoginPath = "/ the Account / MakeLogin"; // unauthenticated guide landing pages, the default of / the Account / the Login 
 . 7 config.Cookie.Name = "lmccookie"; // set a the cookieName 
 . 8 
 . 9}); 
10 services.AddMvc (); 
. 11} 
12 is 
13 is the Configure public void (App IApplicationBuilder, IHostingEnvironment the env) 
14 { 
15 IF (env.IsDevelopment ()) 
16 {
17                 app.UseDeveloperExceptionPage();
18                 app.UseBrowserLink();
19             }
20             else
21             {
22                 app.UseExceptionHandler("/Home/Error");
23             }
24 
25             app.UseStaticFiles();
26             app.UseAuthentication(); //加入认证中间件
27                 ...//// other code
28         }    
Copy the code

Under the test. Direct access Admin / Index is redirected to the Login and return to our definition of the cookie, and then we took cookie access Admin / Index again

 Jwt Token Authentication

  JwtToken generally used for separating some of the front and rear ends of the movable end of the project or project. Processes are generally first user access target resource (e.g. where api / values), then the server returns a response code 401 or 403 identifying unauthorized login. Then the user should re-visit get token (eg api here / token), later got token, token request header to go inside with access to the target resource.

  JwtToken 由三部分构成 首先是HEADER,这里面包含了Base64加密过的 加密算法和token的类型;PAYLOAD ,这里包含了一个Base64加密过的 Claims数组;SIGNATURE,包含了使用你的加密算法加密过后的 HEADER  ‘. ’ 和 PAYLOAD 加一个自定义的密钥。

  我们在.net core 中实现下Jwttoken的验证。

我们在ValuesController 打上[Authorize] 标签。配置我们的startup,在startup ConfigureServices方法中注入认证服务,Configure方法中添加中间件。 此时我们访问api/values=》返回401 的http状态码。

 

Copy the code
 1         public void ConfigureServices(IServiceCollection services)
 2         {
 3             services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings")); //appsettings中读取到jwtsettings节点
 4             var jwtSetting = new JwtSettings();
 5             Configuration.Bind("JwtSettings", jwtSetting);
 6             services.AddAuthentication(options =>
 7             {                                   // 添加认证头
 8                 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
 9                 options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
10             })
11             .AddJwtBearer(jo => jo.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
12             {
13                 ValidIssuer = jwtSetting.Issuer,                    //使用者
14                 ValidAudience = jwtSetting.Audience,                //颁发者
15                 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.SecreKey)) //加密方式
16             });
17             services.AddMvc();
18         }
19 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
20         {
21             if (env.IsDevelopment())
22             {
23                 app.UseDeveloperExceptionPage();
24             }
25             app.UseAuthentication();      //注意加入中间件
Copy the code
Copy the code
    public class JwtSettings
    {
        public string Issuer { get; set; }   //办法token的人
        public string Audience { get; set; } //token使用者
        public string SecreKey { get; set; } //token加密钥
    }
Copy the code
Copy the code
 1 {
 2   "Logging": {
 3     "IncludeScopes": false,
 4     "Debug": {
 5       "LogLevel": {
 6         "Default": "Warning"
 7       }
 8     },
 9     "Console": {
10       "LogLevel": {
11         "Default": "Warning"
12       }
13     }
14   },
15   "JwtSettings": {
16     "Audience": "http://localhost:5000",
17     "Issuer": "http://localhost:5000",
18     "SecreKey": "HelloKeylmclmclmc"
19   }
20 }
Copy the code

 

接下来需要生成token,添加一个AuthorizeController,通过构造函数把jwtsettings 注入进来,添加一个Index的Action 用来生成我们的token。我们需要一个验证下登录用户的用户名密码,所以还需要添加一个ViewModel

Copy the code
    public class LoginViewModel
    {
        [Required]
        public string Name { get; set; }
        [Required]
        public string PassWord { get; set; }
    }
Copy the code
Copy the code
 1         private JwtSettings _jwtSettings;
 2         public AuthorizeController(IOptions<JwtSettings> options)       //构造函数注入,拿到appsettings 里面的jwtsettings
 3         {
 4             _jwtSettings = options.Value;
 5         }
 6         [Route("api/token")]
 7         [HttpPost]
 8         public IActionResult Index(LoginViewModel loginViewModel)
 9         {
10             if (!ModelState.IsValid)
11                 return BadRequest();
12             if (!(loginViewModel.Name == "lmc" && loginViewModel.PassWord == "123456"))
13                 return BadRequest();
14             var claims = new Claim[]                //实例化一个Claim
15             {
16                 new Claim(ClaimTypes.Name,"lmc"),
17                 new Claim(ClaimTypes.Role, "admin")
18             };
19             var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecreKey));  //将appsettings里面的SecreKey拿到
20             var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);             //使用HmacSha256 算法加密
21             //生成token,设置过期时间为30分钟, 需要引用System.IdentityModel.Tokens.Jwt 包
22             var token = new JwtSecurityToken(_jwtSettings.Issuer, _jwtSettings.Audience, claims, DateTime.Now, DateTime.Now.AddMinutes(30), creds);
23             //将token返回
24             return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
25         }
Copy the code

一切准备就绪,拿到Token。带着token来访问 /api/values,注意token需要带这常量 bearer 。

带着我们的加密钥来jwt官网验证一下。 

基于角色(Role),Claim/Policy 的授权:

在我们返回token的时候,实例化过一个Claim数组,其中,Role是admin。我们修改ValuesController的Authorize特性标签( [Authorize(Roles = "user")])。

 

当我们带着token再去验证时候。然后我们把Claim数组的Role那一项的Value 改为user 便会正常认证。

基于Claim的验证我们需要做的事在StartUp的ConfigureServices方法中,将授权模块加入到DI容器中。这里我们添加了一个SuperAdminOnlydPolicy

此时,我们需要在AuthorizeController控制器返回Token的时候,需要在Claim数组中添加一个新的Claim,表示我们的Policy。

此时,再修改我们的ValuesController控制器的Authorize特性标签。

PostMan 走一波===》

 

 Identity +EF Authentication 的认证

  首先,使用net core 的脚手架命令创建一个自带Identity 的mvc项目。然后根据appseetings的数据库配初始化数据库(默认数据库实例是(localdb)\\mssqllocaldb,因为我装vs时候没装这个,所以我换成了.) 。

还原完了数据库,就可以把项目跑起来了,可以根据右上角注册,登录下==》  (其中代码可以自行观看)

然后让我们来自己从头开始实现下这个过程:

可以在上文中Cookie认证的项目中完成,也可以新建一个空的MVC core项目。添加一个Account控制器,其中存在三个方法(action),注册、登录,登出。

Copy the code
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Threading.Tasks;
  5 using Microsoft.AspNetCore.Mvc;
  6 using System.Security.Claims;
  7 using Microsoft.AspNetCore.Authentication.Cookies;
  8 using Microsoft.AspNetCore.Authentication;
  9 using MVCOnCookieBaseStudy.ViewModel;
 10 using Microsoft.AspNetCore.Identity;
 11 using MVCOnCookieBaseStudy.Models;
 12 
 13 namespace MVCOnCookieBaseStudy.Controllers
 14 {
 15     public class AccountController : Controller
 16     {
 17         private UserManager<ApplicationUser> _userManager; //加入Identity自带的注册使用的Manager
 18         private SignInManager<ApplicationUser> _signInManager; //加入Identity自带的登录使用的Manager
 19 
 20         public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
 21         {
 22             _userManager = userManager;
 23             _signInManager = signInManager;
 24         }
 25         /// <summary>
 26         /// 注册页面
 27         /// </summary>
 28         /// <returns></returns>
 29         public IActionResult Register(string returnUrl = "/Home/Index") 
 30         {
 31             ViewData["ReturnUrl"] = returnUrl;
 32             return View();
 33         }
 34         [HttpPost]
 35         public async Task<IActionResult> Register(RegisterViewModel registerViewModel, string returnUrl = "/Home/Index")
 36         {
 37             ViewData["ReturnUrl"] = returnUrl;
 38             if (ModelState.IsValid)  //model 验证
 39             {
 40                 ApplicationUser identityUser = new ApplicationUser
 41                 {
 42                     Email = registerViewModel.Email,
 43                     UserName = registerViewModel.Email,
 44                     NormalizedUserName = registerViewModel.Email
 45                 };
 46                 var result = await _userManager.CreateAsync(identityUser, registerViewModel.Password);
 47                 if (result.Succeeded)
 48                 {
 49                     await _signInManager.SignInAsync(identityUser, new AuthenticationProperties { IsPersistent = true });
 50                     return Redirect(returnUrl);
 51                 }
 52                 else
 53                 {
 54                     foreach(var err in result.Errors)
 55                     {
 56                         ModelState.AddModelError("", err.Description);
 57                     }
 58                 }
 59             }
 60             
 61             return View();
 62         }
 63         /// <summary>
 64         /// 登录页面
 65         /// </summary>
 66         /// <returns></returns>
 67         public IActionResult Login(string returnUrl = "/Home/Index")
 68         {
 69             ViewData["ReturnUrl"] = returnUrl;
 70             return View();
 71         }
 72         [HttpPost]
 73         public async Task<IActionResult> Login(RegisterViewModel LoginViewModel, string returnUrl = "/Home/Index")
 74         {
 75             ViewData["ReturnUrl"] = returnUrl;
 76             var loginUser = await _userManager.FindByEmailAsync(LoginViewModel.Email);
 77             if (loginUser == null)
 78             {
 79                 return View();
 80             }
 81             
 82             await _signInManager.SignInAsync(loginUser, new AuthenticationProperties { IsPersistent = true });
 83             return Redirect(returnUrl);
 84         }
 85         /// <summary>
 86         /// 原来的Cookie登录
 87         /// </summary>
 88         /// <returns></returns>
 89         public async Task<IActionResult> MakeLogin()
 90         {
 91             var claims = new List<Claim>
 92             {
 93                 new Claim(ClaimTypes.Name,"lmc"),       
 94                 new Claim(ClaimTypes.Role, "admin")
 95             };
 96             var claimsIdentity = new ClaimsIdentity(
 97                 claims,
 98                 CookieAuthenticationDefaults.AuthenticationScheme
 99                 );
100             await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
101                 new ClaimsPrincipal(claimsIdentity),
102                 new AuthenticationProperties {
103                     IsPersistent=true,                              //cookie过期时间设置为持久
104                     ExpiresUtc= DateTime.UtcNow.AddSeconds(20)      //设置过期20秒
105                 });
106             return Ok();
107         }
108         /// <summary>
109         /// 登出
110         /// </summary>
111         /// <returns></returns>
112         public async Task<IActionResult> Logout()
113         {
114             await _signInManager.SignOutAsync();
115             return Redirect("/Home/Index");
116         }
117     }
118     //覆盖默认验证
119     public class MyCookieTestAuthorize: CookieAuthenticationEvents
120     {
121         public override Task ValidatePrincipal(CookieValidatePrincipalContext context)
122         {
123             return base.ValidatePrincipal(context);
124         }
125     }
126 }
Copy the code
Copy the code
@using MVCOnCookieBaseStudy.ViewModel
@model RegisterViewModel
@{
    ViewData["Title"] = "Register";
}

<h2>@ViewData["Title"]</h2>

<div class="row">
    <div class="col-md-4">
        <form asp-route-returnUrl="@ViewData["ReturnUrl"]" method="post">
            <h4>Create a new account.</h4>
            <hr />
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Email"></label>
                <input asp-for="Email" class="form-control" />
                <span asp-validation-for="Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Password"></label>
                <input asp-for="Password" class="form-control" />
                <span asp-validation-for="Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="ConfirmPassword"></label>
                <input asp-for="ConfirmPassword" class="form-control" />
                <span asp-validation-for="ConfirmPassword" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-default">Register</button>
        </form>
    </div>
</div>

@section Scripts {
    @await Html.PartialAsync("_ValidationScriptsPartial")
}
Copy the code
Copy the code
 1 @using MVCOnCookieBaseStudy.ViewModel
 2 @model RegisterViewModel
 3 @{
 4     ViewData["Title"] = "Login";
 5 }
 6 
 7 <h2>Login</h2>
 8 
 9 
10 <div class="row">
11     <div class="col-md-4">
12         <section>
13             <form asp-route-returnurl="@ViewData["ReturnUrl"]" method="post">
14                 <h4>Use a local account to log in.</h4>
15                 <hr />
16                 <div asp-validation-summary="All" class="text-danger"></div>
17                 <div class="form-group">
18                     <label asp-for="Email"></label>
19                     <input asp-for="Email" class="form-control" />
20                     <span asp-validation-for="Email" class="text-danger"></span>
21                 </div>
22                 <div class="form-group">
23                     <label asp-for="Password"></label>
24                     <input asp-for="Password" class="form-control" />
25                     <span asp-validation-for="Password" class="text-danger"></span>
26                 </div>
27                 <div class="form-group">
28                     <button type="submit" class="btn btn-default">Log in</button>
29                 </div>
30             </form>
31         </section>
32     </div>
33 </div>
34 @section Scripts{ 
35     @await Html.PartialAsync("_ValidationScriptsPartial");  @*前端验证,需要引用jquery.validate.min.js*@
36 }
Copy the code

这个过程中需要使用到一个ViewModel,用来传递登录数据

Copy the code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel.DataAnnotations;
 4 using System.Linq;
 5 using System.Threading.Tasks;
 6 
 7 namespace MVCOnCookieBaseStudy.ViewModel
 8 {
 9     public class RegisterViewModel
10     {
11         [Required]
12         [EmailAddress]
13         [Display(Name = "Email")]
14         public string Email { get; set; }
15 
16         [Required]
17         [DataType(DataType.Password)]
18         [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
19         [Display(Name = "Password")]
20         public string Password { get; set; }
21 
22         [DataType(DataType.Password)]
23         [Display(Name = "Confirm password")]
24         [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
25         public string ConfirmPassword { get; set; }
26     }
27 }
Copy the code

添加集成自Identity的User 和 Role还有数据库链接上下文

Copy the code
    public class ApplicationUserRole: IdentityRole
    {
    }
    public class ApplicationUser:IdentityUser
    {
    }
Copy the code
Copy the code
1     public class ApplicationDbContext:IdentityDbContext<ApplicationUser,ApplicationUserRole,string>
2     {
3         public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
4         {
5 
6         }
7     }
Copy the code

接下来配置我们的StartUp,在ConfigureServices方法中 将数据库连接上下文加入DI容器,Identity服务加入DI容器,重新配置下我们的密码规则。(注意在Configure加入认证中间件)

Copy the code
 1         public void ConfigureServices(IServiceCollection services)
 2         {
 3             //连接数据库服务加入DI容器
 4             services.AddDbContext<ApplicationDbContext>(option =>
 5             {
 6                 option.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
 7             });
 8             //将Identity服务加入DI容器
 9             services.AddIdentity<ApplicationUser, ApplicationUserRole>()
10                 .AddEntityFrameworkStores<ApplicationDbContext>()
11                 .AddDefaultTokenProviders();
12             //设置注册密码的规则
13             services.Configure<IdentityOptions>(options =>
14             {
Options.Password.RequireLowercase to false = 15; 
16 = options.Password.RequireNonAlphanumeric to false; 
. 17 = options.Password.RequireUppercase to false; 
18 is}); 
. 19 
20 is services.AddAuthentication (CookieAuthenticationDefaults.AuthenticationScheme) 
21 is .AddCookie (config => 
22 is { 
23 config.LoginPath = "/ Account / login "; // unauthenticated guide landing pages, the default is / the Account / the login 
24 config.Cookie.Name = "lmccookie"; // set a the cookieName 
25 
26 is}); 
27 Services .AddMvc (); 
28}
Copy the code

Guess you like

Origin www.cnblogs.com/frank0812/p/11230999.html