我正在尝试使用Bearer令牌和owin进行身份验证 .
我可以使用授权类型 password
并在 AuthorizationServerProvider.cs 中覆盖 GrantResourceOwnerCredentials
来发出令牌 .
但我无法使用 Authorize
属性访问控制器方法 .
这是我的代码:
Startup.cs
public class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
// normal
public Startup() : this(false) { }
// testing
public Startup(bool isDev)
{
// add settings
Settings.Configure(isDev);
OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
}
public void Configuration(IAppBuilder app)
{
// Configure the db context, user manager and role manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.CreatePerOwinContext<LoanManager>(BaseManager.Create);
var config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
// token generation
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AuthenticationType = "Bearer",
AuthenticationMode = AuthenticationMode.Active
});
}
}
AuthorizationServerProvider.cs
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
// enable CORS for all hosts, headers and methods
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.Routes.MapHttpRoute(
name: "optional params",
routeTemplate: "api/{controller}"
);
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// stop cookie auth
config.SuppressDefaultHostAuthentication();
// add token bearer auth
config.Filters.Add(new MyAuthenticationFilter());
//config.Filters.Add(new HostAuthenticationFilter(Startup.OAuthOptions.AuthenticationType));
config.Filters.Add(new ValidateModelAttribute());
if (Settings.IsDev == false)
{
config.Filters.Add(new AuthorizeAttribute());
}
// make properties on model camelCased
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
MyAuthenticationFilter.cs 用于调试目的的自定义过滤器
public class MyAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
{
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
if (context.Principal != null && context.Principal.Identity.IsAuthenticated)
{
}
return Task.FromResult(0);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
}
}
如果我在 MyAuthenticationFilter.cs 中调试 AuthenticateAsync
,我会在请求中看到 Headers :
Authorization: Bearer AQAAANCMnd8BFdERjHoAwE_Cl...
但身份声明为空, context.Principal.Identity.IsAuthenticated
为假 .
有任何想法吗?
4 回答
发布一年后,我也遇到了同样的问题 .
如您所见,我的承载令牌在请求标头中被识别,但我的身份仍然未经过身份验证 .
要解决此问题,简短的答案是确保在配置WebApi中间件(HttpConfiguration)之前配置OAuth中间件 .
我正在寻找相同的解决方案,我花了一个星期左右的时间,我离开了它 . 今天我开始再次搜索,我找到了你的问题,我希望能找到答案 .
所以我花了一整天的时间除了尝试所有可能的解决方案,将建议相互融合之外,我找到了一些解决方案,但是我们找到了很长的解决方法,这就是我所发现的长篇大论 .
首先,如果您需要使用自定义第三方身份提供者令牌对Web站点进行身份验证,则需要使用相同的machineKey,或者您需要将它们都放在同一台服务器上 .
您需要将 machineKey 添加到
system.web
部分,如下所示:Web.Config
这是generate a new machineKey的链接:
现在您需要移动到Startup.Auth.cs文件,您可以在其中找到Startup.cs分部类,您需要定义OAuthBearerOptions
Startup.Auth.cs
使用以下内容替换AccountController中的Login操作:
AccountController.cs
您需要做的最后一件事是将这行代码放在Global.asax.cs中以避免Anti Forgery异常:
Global.asax.cs
希望这对你有用 .
好吧,我一直在研究这个问题已经有一段时间了,我终于找出了什么是错的,现在它正在发挥作用 .
看来你的Cors在GrantResourceOwnerCredentials方法上启用代码会以某种方式从参数中推翻 Headers . 因此,通过将您的第一行放在当前第三行之下,您将解决问题:
到目前为止,我还没有深入了解为什么会这样,但我相信通过在获取userManager之前添加新的标头条目以某种方式破坏客户端上post方法发送的数据,在我的情况下,角度资源如下:
我不确定这是否有帮助,但是我遇到IsAuthenticated在使用依赖注入时返回false的问题(参见SO问题here)并且它看起来因为在注入点它没有被Owin管道设置 .
我通过懒惰注入校长来克服它 . 无论哪种方式,我将一个非常基本的应用程序(在上面链接)放在一起来演示问题,但它可能会帮助你,因为它显示在属性中设置了Principal并使用了承载身份验证 .