zoukankan      html  css  js  c++  java
  • .NET & JWT

    使用 JWT 库

    JWT,a JWT(JSON Web Token) implementation for .NET

    该库支持生成和解析JSON Web Token

    你可以直接通过Nuget获取,也可以自己下载和编译源码.

    // 不要忘了 using
    using JWT;
    using JWT.Algorithms;
    using JWT.Builder;
    
    // 自定义秘钥
    // jwt 的生成和解析都需要使用
    const string secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
    

    创建 JWT

    // 使用 JwtBuilder 来生成 token
    string token = new JwtBuilder()
    	.WithAlgorithm(new HMACSHA256Algorithm()) // 使用算法
    	.WithSecret(secret) // 使用秘钥
    	.AddClaim("exp", DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds())
    	.AddClaim("claim2", "claim2-value")
    	.Build();
    
    Console.WriteLine(token);
    

    生成的 token 如下:

    // 注意:是通过.符号分隔成3段,分别对应的是header.payload.signature
    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1Mjg3MjA2NTEsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.56xcZALlJuwROe3qssCbe_DDjpQShk-Ik7kWAzONWFU
    

    生成后可以分发出去, 别人拿着 token 来请求接口的时候, 我们需要解析验证

    // 使用 JwtBuilder 来解析 token
    try
    {
    	string json = new JwtBuilder()
    		.WithSecret(secret)
    		.MustVerifySignature()
    		.Decode(token);
    	
    	Console.WriteLine(json);
    }
    catch (TokenExpiredException)
    {
    	Console.WriteLine("token 已过期");
    }
    catch (SignatureVerificationException)
    {
    	Console.WriteLine("token 签名无效");
    }
    

    解析后得到的 json 字符串如下:

    {	
    	"exp": 1528721303,
    	"claim2": "claim2-value"
    }
    

    使用 Microsoft.IdentityModel.Tokens 库

    • 新建一个 ASP.NET Core API 项目
    • 新增一个控制器 AuthController

    生成 JWT

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.IdentityModel.Tokens;
    using System;
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Text;
    
    namespace WebApplication1.Controllers
    {
        [ApiController]
        [Route("[controller]/[action]")]
        public class AuthController : Controller
        {
            private readonly IConfiguration _configuration;
    
            public AuthController(IConfiguration configuration)
            {
                _configuration = configuration;
            }
            
            [HttpGet]
            public IActionResult Token()
            {
                var claims = new[]
                {
                    new Claim(type: ClaimTypes.Name, value: "username")
                };
    
                var issuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["IssuerSigningKey"]));
                var creds = new SigningCredentials(issuerSigningKey, SecurityAlgorithms.HmacSha256);
                //.NET Core’s JwtSecurityToken class takes on the heavy lifting and actually creates the token.
                /**
                 * Claims (Payload)
                    Claims 部分包含了一些跟这个 token 有关的重要信息。 JWT 标准规定了一些字段,下面节选一些字段:
                    iss: The issuer of the token,token 是给谁的
                    sub: The subject of the token,token 主题
                    exp: Expiration Time。 token 过期时间,Unix 时间戳格式
                    iat: Issued At。 token 创建时间, Unix 时间戳格式
                    jti: JWT ID。针对当前 token 的唯一标识
                    除了规定的字段外,可以包含其他任何 JSON 兼容的字段。
                 * */
                var token = new JwtSecurityToken(
                    issuer: "test.com", // 
                    audience: "test.com",
                    claims: claims,
                    expires: DateTime.Now.AddMinutes(1),
                    signingCredentials: creds);
    
                return Ok(new
                {
                    access_token = new JwtSecurityTokenHandler().WriteToken(token: token)
                });
            }
        }
    }
    

    生成的 JWT 可以放到 jwt.io 里验证一下.

    使用 IdentityServer4 库

    IdentityServerTools 是 IdentityServer4 中的一个工具类, 封装了 JWT 生成方法, 以便使用.

    按照套路, 注入 IdentityServer4 服务, 这里我们仅使用工具类来生成 JWT, 所以不需要配置其他东西.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddIdentityServer()
            .AddDeveloperSigningCredential();
        // 省略其他
    }
    

    在控制器中构造函数注入使用

    using IdentityServer4;
    using Microsoft.AspNetCore.Mvc;
    using System;
    using System.Security.Claims;
    using System.Threading.Tasks;
    
    // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
    
    namespace WebApplication1.Controllers
    {
        [ApiController]
        [Route("api/[controller]")]
        public class AuthController : ControllerBase
        {
            private readonly IdentityServerTools _identityServerTools;
    
            public AuthController(IdentityServerTools identityServerTools)
            {
                _identityServerTools = identityServerTools;
            }
    
            [HttpGet]
            public async Task<IActionResult> TokenAsync()
            {
    			// 完整的场景, 应该验证用户密码
                Claim[] claims = new Claim[]
                {
                    new Claim(type: ClaimTypes.NameIdentifier, value: Guid.NewGuid().ToString("N")),
                    new Claim(type: ClaimTypes.Name, value: "admin"),
                    new Claim(type: ClaimTypes.Gender, value: "man"),
                    new Claim(type: ClaimTypes.Email, value: "xxx@xxx.com"),
                    new Claim(type: "custom", value: "value"),
                };            
                
    			// 可以按自己需求, 返回指定结构的数据
    			return Ok(value: await _identityServerTools.IssueJwtAsync(lifetime: 3600, claims: claims));			
            }
        }
    }
    

    这个时候访问 /api/auth 应该就能看到一段老长老长的 JWT 了, 可以扔到 jwt.io 里验证下.

    身份认证

    上面介绍了几种不同库生成 JWT 的方法, 当别人拿着我们分发出去的 JWT 来访问我们的接口时, 需要对其进行身份认证

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using Microsoft.IdentityModel.Tokens;
    
    namespace WebApplication1
    {
        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(options =>
                {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                }).AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = false, // 是否验证 Issuer
                        ValidIssuer = "test.com",
                        ValidateAudience = false, // 是否验证 Audience
                        ValidAudience = "",
                        ValidateIssuerSigningKey = true, // 是否验证签名秘钥
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["IssuerSigningKey"])),
                        ValidateLifetime = true, // 是否验证失效时间
                    };
                });
                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)
            {
                app.UseAuthentication(); // 使用身份验证
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseMvc();
            }
        }
    }
    

    参考

  • 相关阅读:
    df
    浅谈C#垃圾回收
    eclipse+ADT 进行android应用签名详解
    Android Monkey工具参数意义
    Android Monkey(转载)
    清理Win7右键菜单里“发送到”选项
    Android中LOG机制详解(上)  
    关于微博内容中的短地址ShortURL
    Android中LOG机制详解(下)
    黑盒测试用例设计方法实践(判定表驱动法)
  • 原文地址:https://www.cnblogs.com/taadis/p/12125863.html
Copyright © 2011-2022 走看看