Fork me on GitHub

WebApi使用JWT认证(二)

这是第二部:实现NetCore上的WebApi使用JWT认证

1、NetCore新建一个WebApi的项目

2、打开AppSettings.json,添加Jwt的信息,这里为了演示而已

{
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  },
  "JwtSettings": {
    "Issuer": "XXX",
    "Audience": "XXXX",
    "SecretKey": "To live is to change the world!"
  }
}

3、Models下新建两个类,一个用于登录,一个用于获取配置文件中的值

1 namespace NerCoreJwt.Models
2 {
3     public class LoginViewModel
4     {
5         public string UserName { get; set; } = "wangshibang";
6 
7         public string Password { get; set; } = "123456";
8     }
9 }
 1 namespace NerCoreJwt.Models
 2 {
 3     public class JwtSettings
 4     {
 5         /// <summary>
 6         /// 证书颁发者
 7         /// </summary>
 8         public string Issuer { get; set; }
 9 
10         /// <summary>
11         /// 允许使用的角色
12         /// </summary>
13         public string Audience { get; set; }
14 
15         /// <summary>
16         /// 加密字符串
17         /// </summary>
18         public string SecretKey { get; set; }
19     }
20 
21 }

4、新建一个Controller,用来写登录后生成Token逻辑

 1 using Microsoft.AspNetCore.Mvc;
 2 using Microsoft.Extensions.Options;
 3 using Microsoft.IdentityModel.Tokens;
 4 using NerCoreJwt.Models;
 5 using System;
 6 using System.IdentityModel.Tokens.Jwt;
 7 using System.Security.Claims;
 8 using System.Text;
 9 
10 namespace NerCoreJwt.Controllers
11 {
12     [Route("api/[controller]/[action]")]
13     public class AuthorizeController : Controller
14     {
15         private JwtSettings setting;
16         public AuthorizeController(IOptions<JwtSettings> options)
17         {
18             setting = options.Value;
19         }
20 
21         [HttpPost]
22         public IActionResult Login(LoginViewModel login)
23         {
24             if (ModelState.IsValid)
25             {
26                 if (login.UserName == "wangshibang" && login.Password == "123456")
27                 {
28                     var claims = new Claim[] {
29                         new Claim(ClaimTypes.Name, login.UserName),
30                         new Claim(ClaimTypes.Role, "admin, Manage")
31                     };
32                     var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey));
33                     var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
34                     var token = new JwtSecurityToken(
35                         setting.Issuer,
36                         setting.Audience,
37                         claims,
38                         DateTime.Now,
39                         DateTime.Now.AddMinutes(30),
40                         creds);
41                     return Ok(new { Token = new JwtSecurityTokenHandler().WriteToken(token) });
42                 }
43             }
44             return BadRequest();
45         }
46 
47         [HttpGet]
48         public IActionResult NoValidate()
49         {
50             return Ok();
51         }
52     }
53 }

5、StartUp类里面添加从Configure<JwtSettings>中获取Section才可以使用IOptions获取里面的内容,为了省事就全部贴出来了

 1 using Microsoft.AspNetCore.Authentication.JwtBearer;
 2 using Microsoft.AspNetCore.Builder;
 3 using Microsoft.AspNetCore.Hosting;
 4 using Microsoft.Extensions.Configuration;
 5 using Microsoft.Extensions.DependencyInjection;
 6 using NerCoreJwt.Models;
 7 using System.Linq;
 8 using System.Threading.Tasks;
 9 
10 namespace NerCoreJwt
11 {
12     public class Startup
13     {
14         public Startup(IConfiguration configuration)
15         {
16             Configuration = configuration;
17         }
18 
19         public IConfiguration Configuration { get; }
20 
21         // This method gets called by the runtime. Use this method to add services to the container.
22         public void ConfigureServices(IServiceCollection services)
23         {
24             services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings"));
25             JwtSettings setting = new JwtSettings();
26             Configuration.Bind("JwtSettings", setting);
27             services.AddAuthentication(option =>
28             {
29                 option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
30                 option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
31             }).AddJwtBearer(config =>
32             {
33                 /*
34                 config.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
35                 {
36                     ValidAudience = setting.Audience,
37                     ValidIssuer = setting.Issuer,
38                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey))
39                 };
40                 */
41                 config.SecurityTokenValidators.Clear();
42                 config.SecurityTokenValidators.Add(new MyTokenValidate());
43                 config.Events = new JwtBearerEvents()
44                 {
45                     OnMessageReceived = context =>
46                     {
47                         var token = context.Request.Headers["myToken"];
48                         context.Token = token.FirstOrDefault();
49                         return Task.CompletedTask;
50                     }
51                     
52                 };
53             });
54 
55             services.AddMvc();
56         }
57 
58         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
59         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
60         {
61             if (env.IsDevelopment())
62             {
63                 app.UseDeveloperExceptionPage();
64             }
65             app.UseAuthentication();
66             app.UseMvc();
67         }
68     }
69 }

6、Token生成了,可以用PostMan调用接口试试,把生成的Token粘到jwt.io官网看看里面的信息

下面我们来进行授权

7、为了自定义授权方法,我们需要新建一个类,继承自ISecurityTokenValidator接口

 1 using Microsoft.AspNetCore.Authentication.JwtBearer;
 2 using Microsoft.IdentityModel.Tokens;
 3 using System.IdentityModel.Tokens.Jwt;
 4 using System.Linq;
 5 using System.Security.Claims;
 6 
 7 namespace NerCoreJwt
 8 {
 9     public class MyTokenValidate : ISecurityTokenValidator
10     {
11         public bool CanValidateToken => true;
12 
13         public int MaximumTokenSizeInBytes { get ; set ; }
14 
15         public bool CanReadToken(string securityToken)
16         {
17             return true;
18         }
19 
20         public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
21         {
22             ClaimsPrincipal principal;
23             try
24             {
25                 validatedToken = null;
26                 //这里需要验证生成的Token
27                 /*
28 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoid2FuZ3NoaWJhbmciLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJhZG1pbiwgTWFuYWdlIiwibmJmIjoxNTIyOTI0MDgxLCJleHAiOjE1MjI5MjU4ODEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMCIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMCJ9.fa0jDYt_MqHFcwQfsMS30eCsjEwQt_uiv96bGtMQJBE
29                 */
30                 var token = new JwtSecurityToken(securityToken);
31                 //获取到Token的一切信息
32                 var payload = token.Payload;
33                 var role = (from t in payload where t.Key == ClaimTypes.Role select t.Value).FirstOrDefault();
34                 var name = (from t in payload where t.Key == ClaimTypes.Name select t.Value).FirstOrDefault();
35                 var issuer = token.Issuer;
36                 var key = token.SecurityKey;
37                 var audience = token.Audiences;
38                 var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
39                 identity.AddClaim(new Claim(ClaimTypes.Name, name.ToString()));
40                 identity.AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, "admin"));
41                 principal = new ClaimsPrincipal(identity);
42             }
43             catch
44             {
45                 validatedToken = null;48                 principal = null;
49             }
50             return principal;
51         }
52     }
53 }

8、然后注释掉上面代码我注册的部分,因为这是原生的Authorize验证特性,添加后面的自定义验证逻辑

9、在接口上面添加Authorize特性,用PostMan调用接口传入生成的Token,设置断点看看效果吧

 1 using Microsoft.AspNetCore.Authorization;
 2 using Microsoft.AspNetCore.Mvc;
 3 using System.Collections.Generic;
 4 
 5 namespace NerCoreJwt.Controllers
 6 {
 7     [Route("api/[controller]")]
 8     public class ValuesController : Controller
 9     {
10         // GET api/values
11         [Authorize(Roles = "admin")]
12         [HttpGet]
13         public IEnumerable<string> Get()
14         {
15             return new string[] { "value1", "value2" };
16         }
17 
18         // GET api/values/5
19         [HttpGet("{id}")]
20         public string Get(int id)
21         {
22             return "value";
23         }
24 
25         // POST api/values
26         [HttpPost]
27         public void Post([FromBody]string value)
28         {
29         }
30 
31         // PUT api/values/5
32         [HttpPut("{id}")]
33         public void Put(int id, [FromBody]string value)
34         {
35         }
36 
37         // DELETE api/values/5
38         [HttpDelete("{id}")]
39         public void Delete(int id)
40         {
41         }
42     }
43 }
posted @ 2018-04-07 20:05  雪山玉龙  阅读(...)  评论(...编辑  收藏