- 首先在Visual Studio中創建一個WebApi項目;
- 引入nuget包:Microsoft.AspNetCore.Authentication.JwtBearer
- 在appsetting.json中配置jwt參數
"tokenConfig": {
"secret": "D96BFA5B-F2AF-45BC-9342-5A55C3F9BBB0",
"issuer": "test.cn",
"audience": "test",
"accessExpiration": 30,
"refreshExpiration": 60
}
- 編寫對應的token對象:
using Newtonsoft.Json;
namespace JwtDemo
{
public class TokenManagement
{
[JsonProperty("secret")]
public string Secret { get; set; }
[JsonProperty("issuer")]
public string Issuer { get; set; }
[JsonProperty("audience")]
public string Audience { get; set; }
[JsonProperty("accessExpiration")]
public int AccessExpiration { get; set; }
[JsonProperty("refreshExpiration")]
public int RefreshExpiration { get; set; }
}
}
- 在Startup中配置啟用token認證
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using static JwtDemo.LoginRequestDTO;
namespace JwtDemo
{
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.AddControllers();
services.Configure<TokenManagement>(Configuration.GetSection("tokenConfig"));
var token = Configuration.GetSection("tokenConfig").Get<TokenManagement>();
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
//Token Validation Parameters
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
//獲取或設置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用於簽名驗證。
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.
GetBytes(token.Secret)),
//獲取或設置一個System.String,它表示將使用的有效發行者檢查代幣的發行者。
ValidIssuer = token.Issuer,
//獲取或設置一個字符串,該字符串表示將用於檢查的有效受眾反對令牌的觀眾。
ValidAudience = token.Audience,
ValidateIssuer = false,
ValidateAudience = false,
};
});
services.AddScoped<IAuthenticateService, TokenAuthenticationService>();
services.AddScoped<IUserService, UserService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
- 編寫認證服務接口及服務類
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace JwtDemo
{
public interface IAuthenticateService
{
bool IsAuthenticated(LoginRequestDTO request, out string token);
}
public class LoginRequestDTO
{
[Required]
[JsonProperty("username")]
public string Username { get; set; }
[Required]
[JsonProperty("password")]
public string Password { get; set; }
/// <summary>
/// token認證服務
/// </summary>
public class TokenAuthenticationService : IAuthenticateService
{
private readonly IUserService _userService;
private readonly TokenManagement _tokenManagement;
public TokenAuthenticationService(IUserService userService, IOptions<TokenManagement> tokenManagement)
{
_userService = userService;
_tokenManagement = tokenManagement.Value;
}
public bool IsAuthenticated(LoginRequestDTO request, out string token)
{
token = string.Empty;
if (!_userService.IsValid(request))
return false;
var claims = new[]
{
new Claim(ClaimTypes.Name,request.Username)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenManagement.Secret));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var jwtToken = new JwtSecurityToken(_tokenManagement.Issuer, _tokenManagement.Audience, claims,
expires: DateTime.Now.AddMinutes(_tokenManagement.AccessExpiration),
signingCredentials: credentials);
token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
return true;
}
}
}
}
- 自定義認證接口及類IUserService和UserService,模擬驗證密碼的過程,這個需要在Startup中配置注入服務
namespace JwtDemo
{
public interface IUserService
{
bool IsValid(LoginRequestDTO req);
}
public class UserService : IUserService
{
//模擬測試,默認都是人為驗證有效
public bool IsValid(LoginRequestDTO req)
{
return true;
}
}
}
- 添加AuthenticationController,用於根據用戶名和密碼獲取token
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace JwtDemo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AuthenticationController : ControllerBase
{
private readonly IAuthenticateService _authService;
public AuthenticationController(IAuthenticateService authService)
{
this._authService = authService;
}
[AllowAnonymous]
[HttpPost, Route("requestToken")]
public ActionResult RequestToken([FromBody] LoginRequestDTO request)
{
if (!ModelState.IsValid)
{
return BadRequest("Invalid Request");
}
string token;
if (_authService.IsAuthenticated(request, out token))
{
return Ok(token);
}
return BadRequest("Invalid Request");
}
}
}
- 測試:測試之前先給WeatherForecastController加上[Authorize],身份驗證之后才能訪問
- 先訪問https://localhost:44324/weatherforecast,結果為401,未授權,
- 下面請求token:
獲取到token:
帶token訪問被保護的webapi:
成功獲取到webapi數據:
通過學習了解了基本的jwt認證的使用方法
學會了在Fiddler中測試webapi
源碼:https://gitee.com/Alexander360/LearnIdentity/tree/master/LearnIdentity