我有一个使用 ASP.NET MVC 5 创建的稍微旧的 Web 应用程序。已使用 ASP.NET Core 6 Web API 创建了一个新的 Web 服务,并使用 JWT 进行保护,需要将其集成到此 Web 应用程序中。
这可能吗?如果是的话,有人可以引导我找到一些资源吗?我搜索了很多但找不到任何东西。谢谢。
一个最小的例子:
API端:
令牌服务:
public interface ITokenService
{
string GenerateAccessToken(IEnumerable<Claim> claims);
string GenerateRefreshToken();
ClaimsPrincipal GetPrincipalFromExpiredToken(string token);
}
public class TokenService : ITokenService
{
public string GenerateAccessToken(IEnumerable<Claim> claims)
{
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("yourkeyhere"));
var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
var tokeOptions = new JwtSecurityToken(
issuer: "Issuer",
audience: "Audience",
claims: claims,
expires: DateTime.Now.AddMinutes(20),
signingCredentials: signinCredentials
); ;
var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
return tokenString;
}
public string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
}
public ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = "Issuer",
ValidAudience = "Audience",
ValidateAudience = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("yourkeyhere")),
ValidateLifetime = false
};
var tokenHandler = new JwtSecurityTokenHandler();
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken);
var jwtSecurityToken = securityToken as JwtSecurityToken;
if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
throw new SecurityTokenException("Invalid token");
return principal;
}
}
程序.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers().AddJsonOptions(op=>op.JsonSerializerOptions.PropertyNamingPolicy=null);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = "Issuer",
ValidAudience = "Audience",
IssuerSigningKey = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes("yourkeyhere")),
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
ValidateIssuerSigningKey = true
};
});
//since you are fecthing token from another site,it's necessary to enable cors here
builder.Services.AddCors(op=>op.AddPolicy("MyPolicy",x=>x.AllowAnyOrigin()
.AllowAnyMethod().AllowAnyHeader()));
builder.Services.AddScoped<ITokenService, TokenService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseRouting();
app.UseCors("MyPolicy");
app.UseAuthorization();
app.MapControllers();
app.Run();
控制器:
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
private readonly ITokenService _tokenService;
public LoginController(ITokenService tokenService)
{
_tokenService = tokenService;
}
[HttpPost]
public IActionResult Login([FromBody] User user)
{
//check name/password here
if (user.UserName is null)
return Unauthorized();
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName),
};
var accessToken = _tokenService.GenerateAccessToken(claims);
var refreshToken = _tokenService.GenerateRefreshToken();
//you may store refresh token in db with userid/ip....
return new JsonResult(new
{
AccessToken = accessToken,
RefreshToken = refreshToken
});
}
[HttpPost]
[Route("refresh")]
public IActionResult Refresh([FromBody] TokenModel tokenModel)
{
//if refresh token is valid,read claims from expired access token
string accessToken = tokenModel.AccessToken;
string refreshToken = tokenModel.RefreshToken;
var principal = _tokenService.GetPrincipalFromExpiredToken(accessToken);
var username = principal.Identity.Name;
//you have to check if user is valid
var newAccessToken = _tokenService.GenerateAccessToken(principal.Claims);
var newRefreshToken = _tokenService.GenerateRefreshToken();
return new JsonResult(new
{
AccessToken = newAccessToken,
RefreshToken = newRefreshToken
});
}
}
public class User
{
public string UserName { get; set; }
public string PassWord { get; set; }
}
public class TokenModel
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
}
在 asp.net MVC 项目中:
<button id="login">Login</button>
<button id="refresh">Refresh</button>
<button id="source"> Access Protected Resource</button>
<script src="~/Scripts/jquery-3.4.1.js"></script>
<script>
$("#login").click(function () {
$.ajax({
url: 'https://localhost:7006/api/Login',
type: 'POST',
data: JSON.stringify({
username: "name",
password: "pwd"
}),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (response) {
console.log(response)
localStorage.setItem("accesstoken", response.AccessToken)
localStorage.setItem("refreshtoken", response.RefreshToken)
}
})
})
$("#refresh").click(function () {
$.ajax({
url: 'https://localhost:7006/api/Login/refresh',
type: 'POST',
data: JSON.stringify({
AccessToken: localStorage.getItem("accesstoken"),
RefreshToken: localStorage.getItem("refreshtoken")
}),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (response) {
console.log(response)
localStorage.setItem("accesstoken", response.AccessToken)
localStorage.setItem("refreshtoken", response.RefreshToken)
}
})
})
$("#source").click(function () {
var auth = "Bearer " + localStorage.getItem("accesstoken")
console.log(auth)
$.ajax({
url: 'https://localhost:7006/weatherforecast',
type: 'GET',
headers: {
"Authorization": auth
},
success: function (resopnse) {
var message=JSON.stringify(resopnse)
alert(message);
}
})
}
)
</script>
结果: