关注this手动和内置令牌身份验证。它在调试模式下完美运行,但在发布模式下,调用TokenEndpointPath会导致
找不到路径'/ bps / oauth / token'的控制器 实现IController。
由于Web.config文件中的WebBaseUri,URI具有/ bps / part。
<appSettings>
<add key="WebBaseUrl" value="/bps/" />
<add key="WebApiBaseUrl" value="/api/" />
<add key="owin:AutomaticAppStartup" value="true" />
<add key="LoginErrorMessage" value="Login or email is wrong" />
Startup类如下:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use<OwinExceptionHandlerMiddleware>();
var container = new WindsorContainer().Install(new WindsorInstaller());
container.Register(Component.For<IAppBuilder>().Instance(app));
var httpDependencyResolver = new WindsorHttpDependencyResolver(container);
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.DependencyResolver = httpDependencyResolver;
app.CreatePerOwinContext(() => container.Resolve<ApplicationUserManager>());
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorControllerActivator(container));
ConfigureOAuthTokenGeneration(app, container);
ConfigureOAuthTokenConsumption(app);
app.UseWebApi(config);
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app, IWindsorContainer container)
{
var OAuthServerOptions = new OAuthAuthorizationServerOptions
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = container.Resolve<IOAuthAuthorizationServerProvider>(),
AccessTokenFormat = container.Resolve<CustomJwtFormat>(),
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
var issuer = ConfigurationManager.AppSettings["ServerAddress"];
string audienceId = ConfigurationManager.AppSettings["AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
}
这是为提供商属性解析的IOAuthAuthorizationServerProvider的实现:
public class OAuthService : OAuthAuthorizationServerProvider
{
private readonly IApplicationUserService _userService;
private readonly ICredentialsValidatior _credentialsValidatior;
public OAuthService(IApplicationUserService userService, ICredentialsValidatior credentialsValidatior)
{
this._userService = userService;
_credentialsValidatior = credentialsValidatior;
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
if (allowedOrigin == null) allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
/* Some user validation logick */
var user = await _userService.FindByNameAsync(context.UserName);
ClaimsIdentity oAuthIdentity = await GenerateUserIdentityAsync(user);
var ticket = new AuthenticationTicket(oAuthIdentity, null);
context.Validated(ticket);
}
private async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUser user)
{
const string authenticationType = "JWT";
var userIdentity = await _userService.CreateIdentityAsync(user, authenticationType);
return userIdentity;
}
}
正在为 AccessTokenFormat 属性解析的类:
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string _issuer;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = ConfigurationManager.AppSettings["AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
此代码在我的本地计算机上运行,并在调试和发布模式下正常工作。
将此代码以调试模式发布到开发服务器时会出现此问题。
我发现在本地计算机上将 AllowInsecureHttp 属性设置为false会导致此错误,但开发服务器上的版本完全相同。我检查了IL代码, AllowInsecureHttp 属性设置为1。
更新
我尝试将/ bps / part添加到TokenEndpointPath但它没有帮助。
由于未知原因,它现在甚至无法在本地工作。 我发现项目的设置是这样的
遗憾的是,我试图在开发服务器上找到这些设置,因为我对IIS缺乏了解,但我没有找到任何内容。
我还尝试检查OWIN管道,发现通过管道传递的URL与Startup.cs中配置的URL相同。
我还在StackOverflow上找到了this个问题。