我继承了一个 .NET 框架 v4.6.1 MVC Web 应用程序。身份验证是Windows auth,我们无权添加IdentityServer 或Azure AD。
我们将在 6 个月内重新编写整个应用程序,但现在我们需要实现一个功能,该功能需要生成 JWT 并将其应用于特定的控制器/操作。
我已经实现了自己的 OAuth 授权服务器,但是当我使用 @x
属性修饰控制器的操作时,HTTP 请求对操作进行了任何拦截。
[Authorize]
Startup.cs
[assembly: OwinStartup(typeof(SomeNamespace.Startup))]
namespace SomeNamespace
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
//removed for brevity...
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new []
{
ConfigurationManager.AppSettings["Jwt-Audience"]
},
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidIssuer = ConfigurationManager.AppSettings["Jwt-Issuer"],
ValidAudience = ConfigurationManager.AppSettings["Jwt-Audience"],
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(ConfigurationManager.AppSettings["Jwt-SigningKey"]))
}
});
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth2/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromSeconds(30),
Provider = new MyOAuthProvider(),
AccessTokenFormat = new MyJwtFormat(ConfigurationManager.AppSettings["Jwt-Issuer"])
});
}
}
public class MyJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private static readonly byte[] _secret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["Jwt-SigningKey"]);
private readonly string _issuer;
public MyJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var securityKey = new SymmetricSecurityKey(_secret);
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
return new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken(_issuer, ConfigurationManager.AppSettings["Jwt-Audience"], data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingCredentials));
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
public class MyOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
//Owin doesn't seem to have any knowledge of my DbContext
var user = context.OwinContext.Get<MyContext>(null).StaffMembers.AsNoTracking().FirstOrDefault(x => x.Username == context.OwinContext.Authentication.User.Identity.Name);
//temp hack to get the user from the DB
user = new MyContext().StaffMembers.AsNoTracking().FirstOrDefault(x => x.Username == "someuser");
if (user == null)
{
context.SetError("invalid_grant", "The user is not a registered");
context.Rejected();
return Task.FromResult<object>(null);
}
var ticket = new AuthenticationTicket(SetClaimsIdentity(context, user), new AuthenticationProperties());
context.Validated(ticket);
return Task.FromResult<object>(null);
}
private static ClaimsIdentity SetClaimsIdentity(OAuthGrantResourceOwnerCredentialsContext context, StaffMember model)
{
var identity = new ClaimsIdentity("JWT");
var claims = new List<Claim>
{
new Claim(ClaimTypes.Sid, model.StaffId.ToString()),
new Claim(ClaimTypes.Name, model.FullName),
new Claim(ClaimTypes.WindowsAccountName, model.Username),
//new Claim(ClaimTypes.Expiration, newExpiry.ToString("yyyy-MM-dd HH:mm:ss")),
};
identity.AddClaims(claims);
return identity;
}
}
Sample controller action
[System.Web.Mvc.HttpGet]
[System.Web.Mvc.Authorize]
public async Task<ActionResult> Something()
{
var result = await _service.SomeMethod();
return new JsonStringResult(result);
}
(尝试使用和不使用此过滤器注册)
FilterConfig.cs