[英].Net Core Web Api - unable to Authorize properly, getting 401
我正在開發一個使用JWT進行身份驗證和授權的.NET Core示例應用程序。 但是在獲取AccessToken和RefereshToken之后,我無法使用[Authorize]
屬性訪問方法。 我嘗試調試,但是找不到我在這里缺少的東西。
您能調查一下我的代碼並識別出什么錯誤嗎?
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
namespace WebApiJwtExample
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add cors
services.AddCors();
services.AddAuthorization(auth =>
{
auth.AddPolicy(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme, new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build());
});
services.AddAuthentication(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidIssuer = "my_api",
ValidAudiences = new[] { "my_spa" },
IssuerSigningKeys = new List<SecurityKey> {
new SymmetricSecurityKey(Encoding.UTF8.GetBytes( "mykeyname") )}
};
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//Configure Cors
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
app.UseAuthentication();
app.UseMvcWithDefaultRoute();
app.Run(async (context) =>
{
context.Response.StatusCode = 404;
await context.Response.WriteAsync("Page not found");
});
}
}
}
TokenController.cs
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
namespace WebApiJwtExample
{
[Route("/api/token")]
public class TokenController : Controller
{
[HttpPost]
public JsonWebToken Create([FromBody]TokenModel obj)
{
User user = obj.grant_type == "refresh_token" ? GetUserByToken(obj.refresh_token) : GetUserByCredentials(obj.username, obj.password);
if (user == null)
throw new UnauthorizedAccessException("No!");
int ageInMinutes = 20; // However long you want...
DateTime expiry = DateTime.UtcNow.AddMinutes(ageInMinutes);
var token = new JsonWebToken
{
access_token = GenerateToken(user, expiry),
expires_in = ageInMinutes * 60
};
if (obj.grant_type != "refresh_token")
token.refresh_token = GenerateRefreshToken(user);
return token;
}
private User GetUserByToken(string refreshToken)
{
string[] Roles = { "Administrator" };
if (refreshToken == "test")
return new User
{
UserName = "test",
permission = "contents",
Roles = Roles
};
return null;
}
private User GetUserByCredentials(string username, string password)
{
string[] Roles = { "Administrator" };
if (username == "test" && password == "dev123")
return new User
{
UserName = "test",
permission = "contents",
Roles = Roles
};
return null;
}
private string GenerateRefreshToken(User user)
{
return "test";
}
public string GenerateToken(User user, DateTime expiry)
{
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(user.UserName, "jwt"));
// TODO: Add whatever claims the user may have...
RsaSecurityKey _key;
string _algorithm = SecurityAlgorithms.RsaSha256Signature;
string _issuer = "my_api";
string _audience = "my_spa";
string keyName = "mykeyname";
var parameters = new CspParameters { KeyContainerName = keyName };
var provider = new RSACryptoServiceProvider(2048, parameters);
_key = new RsaSecurityKey(provider);
SecurityToken token = tokenHandler.CreateJwtSecurityToken(new SecurityTokenDescriptor
{
Audience = _audience,
Issuer = _issuer,
SigningCredentials = new SigningCredentials(_key, _algorithm),
Expires = expiry.ToUniversalTime(),
Subject = identity
});
return tokenHandler.WriteToken(token);
}
}
public class User
{
public string UserName { get; set; }
public string[] Roles { get; set; }
public string permission { get; set; }
}
public class JsonWebToken
{
public string access_token { get; set; }
public string token_type { get; set; } = "bearer";
public int expires_in { get; set; }
public string refresh_token { get; set; }
}
public class TokenModel
{
public string username { get; set; }
public string password { get; set; }
public string client_id { get; set; }
public string grant_type { get; set; }
public string scope { get; set; }
public string refresh_token { get; set; }
}
}
HomeController File.cs (此處授權返回401狀態)
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace WebApiJwtExample
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[Authorize]
public IActionResult GetUserDetails(){
return new ObjectResult(new {
Username = User.Identity.Name
});
}
}
}
有一個GitHub庫在這里 。
GenerateToken()
方法使用RSA算法生成JWT令牌,而身份驗證使用HcmaSha256
來驗證令牌。 更改TokenController
的代碼,如下所示:
public string GenerateToken(User user, DateTime expiry)
{
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(user.UserName, "jwt"));
string _issuer = "dp_portal_api";
string _audience = "dp_portal_spa";
string keyName = mykeyname;
var token = new JwtSecurityToken
(
issuer: _issuer,
audience: _audience,
claims: identity.Claims,
expires: expiry,
notBefore: DateTime.UtcNow,
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(mykeyname)),
SecurityAlgorithms.HmacSha256)
);
return tokenHandler.WriteToken(token);
}
刪除自己的getSavedToken()
並添加三個幫助器函數:
function getSavedToken() {
// return localStorage.getItem("token"); /// remove this line
var token = localStorage.getItem("token");/// get the stored json string
return JSON.parse(token); /// parse token
}
function getSavedAccessToken() {
return getSavedToken().access_token;
}
function saveToken(tokenObj) {
var str = JSON.stringify(tokenObj);
localStorage.setItem("token", str);
return tokenObj;
}
如下更改$.ajaxSetup
:
$.ajaxSetup({
beforeSend: function(xhr) {
if (isUserLoggedIn()) {
/// remove the line below , since we need the access_token only
// xhr.setRequestHeader('Authorization', 'Bearer ' + getSavedToken());
xhr.setRequestHeader('Authorization', 'bearer ' + getSavedAccessToken());
}
}
})
最后,將您的點擊事件功能更改為:
$('#btLogin').click(function() {
$.ajax({
type: "POST",
url: "/api/token",
data: JSON.stringify({ username: $('#username').val(), password: $('#password').val(), grant_type: "password", client_id: "dp_portal_spa" }),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
success: function (token) {
//localStorage.setItem("token", token); //// remove this line
saveToken(token); /// add this line , since the obj cannot be stored directly
$('#btLoginContainer').hide();
$('#btLogoutContainer').show();
var message = "<p>Token received and saved in local storage under the key 'token'</p>";
message += "<p>Token Value: </p><p style='word-wrap:break-word'>" +JSON.stringify(token) + "</p>";
$('#responseContainer').html(message);
},
failure: handleError
});
});
它將按預期工作。 這是屏幕截圖:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.