主页 > imtoken.im官网 > 使用以太坊区块链和 jwt 令牌保证 Asp
使用以太坊区块链和 jwt 令牌保证 Asp
去中心化应用程序 (DApps) 的通用设计不仅依赖于以太坊区块链,还依赖于 API 层。 在这种情况下,DApp 通过用户的以太坊帐户与智能合约交互,并通过为交换用户凭据而发行的 JWT 令牌与 API 层交互。
目标是使用以太坊帐户作为用户凭证来请求 JWT 令牌。
最简单的方法可能是要求用户使用随机生成的数据在以太坊上进行交易,然后在发布 JWT 之前检查交易和随机数据。 这种方法有几个副作用:
这是不切实际的,并且有一些用户体验限制,我们需要一种方法让用户证明他拥有与他想用来登录的帐户相关联的私钥,而不仅仅是(当然)要求私钥,不管他是否交易。
解决方案
Metamask 团队成员 Dan Finlay 的这篇文章启发了我编写本教程。 基本上以太坊区块浏览器api,您的 DApp 可以提示用户使用他的私钥对 SMS 进行签名。 此签名操作不会生成交易,它由 Metamask 附加组件透明地处理(顺便说一句,您的帐户需要解锁)。 签名后,账户、消息和签名被发送到 API Token 端点。 验证方法首先通过接受签名和明文消息作为输入的函数从签名中推导出帐户(也称为公钥)。 如果计算出的以太坊地址与用户提供的账户相同,则为该账户发放 JWT Token。
请务必注意,整个身份验证流程不需要用户名/密码或 OAuth 外部服务。 用于验证用户身份的机制与以太坊用于保证以太坊区块链安全的机制相同。 这要感谢 Go ethereum (Geth) 通过 Metamask 插件在 JSON RPC 中提供 web3.personal.sign。
服务端调用对应的JSON RPC从签名中获取账号:web3.personal.ecrecover。 在本教程中,我们将构建一个 Asp.Net Core 2 项目作为 API 层,并构建一个简单的 HTML/javascript 客户端作为 DApp,以在实践中演示此身份验证过程。
先决条件开始
打开 Visual Studio 2017,创建 EthereumJwtSolution 并添加两个 Asp.Net Core 2 Web 应用程序项目:EthereumJwtApi 和 EthereumJwtClient。 为两个项目选择 Empty Project Scaffold。
EthereumJwtClient 只是一个 HTML/Javascript 客户端。 我们将在 Asp.Net Core 上构建一个客户端应用程序,以便在 IIS Express 上轻松运行它。
我们需要准备 EthereumJwtApi 来创建和处理 JWT 令牌以保护一些安全端点。 这个任务很简单,因为 Asp.Net Core 2 有一个内置的 JWT 机制,可以插入到我们的应用程序中。 打开Startup.cs,修改ConfigureServices方法:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.Build());
});
services.AddMvc();
然后修改Configure方法:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseMvc();
我们告诉我们的 API 应用程序使用 JWT 身份验证服务。 为了与我们的用户一起工作,我们还需要配置 Cors 策略。 我们在 appsetting.json 中定义设置 JWT 配置:
"Jwt": {
"Key": "averysecretpassphrase", // A random and secure passhphrase
"Issuer": "http://localhost:49443/", // This API base URI
"Audience": "http://localhost:51149/" // The client base URI
},
创建一个简单的可能安全的端点用于测试目的:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet, Authorize]
public IEnumerable Get()
{
return new string[] { "Secret 1", "Secret 2" };
}
}
TokenController.cs 将处理 JWT 请求和相关令牌问题:
[Route("api/[controller]")]
public class TokenController : Controller
{
private IConfiguration _config;
public TokenController(IConfiguration config)
{
_config = config;
}
[AllowAnonymous]
[HttpPost]
public async Task CreateToken([FromBody]LoginVM login)
{
var user = await Authenticate(login);
if (user != null)
{
var tokenString = BuildToken(user);
return Ok(new { token = tokenString });
}
return Unauthorized();
}
private string BuildToken(UserVM user)
{
var claims = new[] {
new Claim(JwtRegisteredClaimNames.Sub, user.Account),
new Claim(JwtRegisteredClaimNames.GivenName, user.Name),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Audience"],
claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
private async Task Authenticate(LoginVM login)
{
// TODO: this method will authenticate the user recovering the Ethereum address from signature using the Geth RPC web3.personal.ecrecover API
UserVM user = user = new UserVM { Account = login.Account, Name = string.Empty, Email = string.Empty };
return user;
}
private async Task Authenticate2(LoginVM login)
{
// TODO: This method will authenticate the user recovering his Ethereum address through underlaying offline ecrecover method.
UserVM user = user = new UserVM { Account = login.Account, Name = string.Empty, Email = string.Empty };
return user;
}
这是一个典型的 JWT 控制器,核心方法 Authenticate 和 Authenticate2 还没有实现。 一旦实施,他们将做同样的工作:从签名中恢复以太坊地址,并检查它是否等于客户端提供的以太坊地址。
LoginVM代表客户端提供的用户凭证以太坊区块浏览器api,UserVM代表“服务器端”登录用户:
public class LoginVM
{
public string Signer { get; set; } // Ethereum account that claim the signature
public string Signature { get; set; } // The signature
public string Message { get; set; } // The plain message
public string Hash { get; set; } // The prefixed and sha3 hashed message
}
public class UserVM
{
public string Account { get; set; } // Unique account name (the Ethereum account)
public string Name { get; set; } // The user name
public string Email { get; set; } // The user Email
}
Authenticate 方法将使用 Signature 和 Message 属性作为 ecRecover 函数的输入,Authenticate2 方法将使用 Signature 和 Hash 属性。 我稍后会解释其中的区别。
================================================ == =====================
分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程: