从 OWIN Cookie 获取不记名令牌并将其放在 API 请求中
Posted
技术标签:
【中文标题】从 OWIN Cookie 获取不记名令牌并将其放在 API 请求中【英文标题】:Get bearer token from OWIN Cookie and put it on API Requests 【发布时间】:2015-10-11 13:49:47 【问题描述】:这是我的场景: 我有一个 MVC4.5/WebApi2 应用程序,它使用基于 Thinktecture.IdentityServer 提供程序的 OpenIdConnectAuthentication。到目前为止,我可以针对 MVC 进行身份验证。现在我想使用 Bearer Token 对 WebApi 进行身份验证。这是我的配置
app.UseWebApi(ConfigureAPI());
app.UseCookieAuthentication(new CookieAuthenticationOptions()
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
CookieSecure = CookieSecureOption.Always,
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
CookieHttpOnly = true
);
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions()
EnableValidationResultCache = false,
Authority = WebConfigurationManager.AppSettings["Authority"],
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive
);
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions()
Authority = WebConfigurationManager.AppSettings["Authority"],
ClientId = WebConfigurationManager.AppSettings["ClientId"],
ClientSecret = WebConfigurationManager.AppSettings["ClientSecret"],
ResponseType = "code id_token",
Scope = "openid email profile",
SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
Notifications = new OpenIdConnectAuthenticationNotifications
AuthenticationFailed = OnAuthenticationFailed,
AuthorizationCodeReceived = OnAuthorizationCodeReceived,
RedirectToIdentityProvider = OnRedirectToIdentityProvider
;
);
还有我的 WebApi 配置
public HttpConfiguration ConfigureAPI()
var httpConfig = new HttpConfiguration();
// Configure Web API to use only bearer token authentication.
httpConfig.SuppressDefaultHostAuthentication();
httpConfig.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
httpConfig.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// Web API routes
httpConfig.MapHttpAttributeRoutes();
httpConfig.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/controller/id",
defaults: new id = RouteParameter.Optional
);
return httpConfig;
由于我的 OWIN Cookie 中已经有访问令牌,我想在授权标头到达 API 之前将其添加到授权标头中,从而获得成功的身份验证。
这是我尝试过的
public class CustomAuthorizeAttribute : AuthorizeAttribute
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
var cookies = actionContext.Request.Headers.GetCookies(".AspNet.Cookies");
var cookie = cookies.First().Cookies.FirstOrDefault(c => c.Name == ".AspNet.Cookies");
if (cookie != null)
var unprotectedTicket = Startup.OAuthOptions.TicketDataFormat.Unprotect(ticket);
actionContext.Request.Headers.Add("Authorization", string.Format("Bearer 0", unprotectedTicket.Identity.Claims.First(c => c.Type == "access_token").Value));
return base.IsAuthorized(actionContext);
我什至尝试使用放在app.UseWebApi(ConfigureAPI());
之后的 OWIN 中间件
public class UseCookieToBearerAuthentication : OwinMiddleware
public UseCookieToBearerAuthentication(OwinMiddleware next) : base(next)
public async override Task Invoke(IOwinContext context)
//TODO Retrieve cookie name from somewhere like in FormsAuthentication.FormsCookieName
var cookies = context.Request.Cookies;
var cookie = cookies.FirstOrDefault(c => c.Key == ".AspNet.Cookies");
if (!cookie.Equals(default(KeyValuePair<string, string>)))
var ticket = cookie.Value;
var unprotectedTicket = Startup.OAuthOptions.TicketDataFormat.Unprotect(ticket);
context.Request.Headers.Add("Authorization", new string[]
string.Format("Bearer 0", unprotectedTicket.Identity.Claims.First(c => c.Type == "access_token").Value)
);
await Next.Invoke(context);
那么,如何根据我的 Owin Cookie 中的访问令牌为我的 web api 实现令牌身份验证?
提前致谢。
【问题讨论】:
【参考方案1】:问题在于 IdentityServerBearerTokenAuthenticationOptions 默认使用 AuthenticationMode = ValidationMode.ValidationEndpoint;
,而默认使用 Microsoft.Owin.Security.AuthenticationMode.Active
并且不能被覆盖。
所以我将 IdentityServerBearerTokenAuthenticationOptions 设置为 ValidationMode = ValidationMode.Local;
和 AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive;
,这很好,因为访问令牌是 JWT(自包含)。
我还使用 OWIN 中间件从请求上的 cookie 中获取访问令牌,并将其设置在自动化标头上。
public class UseCookieToBearerAuthentication : OwinMiddleware
public UseCookieToBearerAuthentication(OwinMiddleware next) : base(next)
public async override Task Invoke(IOwinContext context)
var x = Startup.OAuthOptions.CookieName;
var cookieName = string.Format("01", CookieAuthenticationDefaults.CookiePrefix, CookieAuthenticationDefaults.AuthenticationType);
var cookies = context.Request.Cookies;
var cookie = cookies.FirstOrDefault(c => c.Key == ".AspNet.Cookies");
if (!cookie.Equals(default(KeyValuePair<string, string>)))
var ticket = cookie.Value;
var unprotectedTicket = Startup.OAuthOptions.TicketDataFormat.Unprotect(ticket);
context.Request.Headers.Add("Authorization", new string[]
string.Format("Bearer 0", unprotectedTicket.Identity.Claims.First(c => c.Type == "access_token").Value)
);
await Next.Invoke(context);
【讨论】:
我们实际上希望摆脱用于 Web API 的 cookie - 这是一种反模式并且容易受到 CSRF 攻击。如果您绝对想使用 cookie,请使用 Web API 中的 cookie 中间件 - 否则不要使用 cookie 并通过显式身份验证正确执行 - leastprivilege.com/2015/04/01/…以上是关于从 OWIN Cookie 获取不记名令牌并将其放在 API 请求中的主要内容,如果未能解决你的问题,请参考以下文章
实施 Identity 2.1 + OWIN OAuth JWT 不记名令牌时如何从 Web API 控制器端点进行身份验证