OWIN 多應用不記名令牌認證
我想對 VS 2013 中 ASP.NET 的預設單頁應用程序模板進行修改,該模板目前使用不記名令牌身份驗證。該範例使用 app.UseOAuthBearerTokens 創建令牌伺服器和中間件,以驗證同一應用程序中請求的令牌。
我想做的是保留它,但添加第二個應用程序(在 IIS 中綁定到同一個域,不同的路徑 - 例如 /auth/* 用於身份驗證伺服器, /app1/* 用於應用程序)。對於第二個應用程序,我希望它接受由第一個應用程序中的身份驗證伺服器發出的令牌。這怎麼可能實現?我在 Startup.Auth.cs 中嘗試了以下操作,只是從 UseOAuthBearerTokens 中的程式碼開始,但我得到了對任何請求的 401 響應
$$ Authorize $$屬性:
public partial class Startup { static Startup() { PublicClientId = "self"; UserManagerFactory = () => new UserManager<IdentityUser>(new UserStore<IdentityUser>()); OAuthOptions = new OAuthAuthorizationServerOptions { //TokenEndpointPath = new PathString("/Token"), Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory), //AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), //AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active, AuthenticationType = "ExternalBearer", AllowInsecureHttp = true, }; } public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; } public static Func<UserManager<IdentityUser>> UserManagerFactory { get; set; } public static string PublicClientId { get; private set; } // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { //// Enable the application to use a cookie to store information for the signed in user //// and to use a cookie to temporarily store information about a user logging in with a third party login provider //app.UseCookieAuthentication(new CookieAuthenticationOptions()); //app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); OAuthBearerAuthenticationOptions bearerOptions = new OAuthBearerAuthenticationOptions(); bearerOptions.AccessTokenFormat = OAuthOptions.AccessTokenFormat; bearerOptions.AccessTokenProvider = OAuthOptions.AccessTokenProvider; bearerOptions.AuthenticationMode = OAuthOptions.AuthenticationMode; bearerOptions.AuthenticationType = OAuthOptions.AuthenticationType; bearerOptions.Description = OAuthOptions.Description; bearerOptions.Provider = new CustomBearerAuthenticationProvider(); bearerOptions.SystemClock = OAuthOptions.SystemClock; OAuthBearerAuthenticationExtensions.UseOAuthBearerAuthentication(app, bearerOptions); } } public class CustomBearerAuthenticationProvider : OAuthBearerAuthenticationProvider { public override Task ValidateIdentity(OAuthValidateIdentityContext context) { var claims = context.Ticket.Identity.Claims; if (claims.Count() == 0 || claims.Any(claim => claim.Issuer != "LOCAL AUTHORITY")) context.Rejected(); return Task.FromResult<object>(null); } }顯然我錯過了第二個應用程序有某種方式驗證令牌來自第一個應用程序的部分。某種公共簽名密鑰?
這只是為了概念證明。
編輯:機器密鑰建議在 POC 展示中執行良好,很高興知道有支持其他關鍵場景的 AS 實現選項。
我能夠使用此站點生成展示密鑰(不用於生產):http: //aspnetresources.com/tools/machineKey
並將結果放在
<system.web>IIS 站點中託管的每個應用程序的 web.config 元素下。我還必須在資源伺服器的 Startup 類中刪除一些特定於 AS 的配置選項。
目前,中間件(或者更確切地說是生成的令牌)並不是真正設計為跨應用程序工作的。對於這些場景,您應該使用真正的授權伺服器(例如https://github.com/thinktecture/Thinktecture.AuthorizationServer)。
也就是說,您可以通過在兩個應用程序中同步機器密鑰(web.config 中的 machineKey 元素)來使其工作。但我從未嘗試過。
預設情況下,當託管在 IIS 上時,OWIN 使用 ASP.NET 機器密鑰數據保護來保護 OAuth 訪問令牌。您可以使用 System.Web.dll 中的 MachineKey 類來取消對令牌的保護。
public class MachineKeyProtector : IDataProtector { private readonly string[] _purpose = { typeof(OAuthAuthorizationServerMiddleware).Namespace, "Access_Token", "v1" }; public byte[] Protect(byte[] userData) { throw new NotImplementedException(); } public byte[] Unprotect(byte[] protectedData) { return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose); } }然後,構造一個 TicketDataFormat 來獲取 AuthenticationTicket 對象,您可以在其中獲取 ClaimsIdentity 和 AuthenticationProperties。
var access_token="your token here"; var secureDataFormat = new TicketDataFormat(new MachineKeyProtector()); AuthenticationTicket ticket = secureDataFormat.Unprotect(access_token);要取消保護其他 OAuth 令牌,您只需更改 _purpose 內容。有關詳細資訊,請參閱此處的 OAuthAuthorizationServerMiddleware 類:http: //katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerMiddleware.cs
if (Options.AuthorizationCodeFormat == null) { IDataProtector dataProtecter = app.CreateDataProtector( typeof(OAuthAuthorizationServerMiddleware).FullName, "Authentication_Code", "v1"); Options.AuthorizationCodeFormat = new TicketDataFormat(dataProtecter); } if (Options.AccessTokenFormat == null) { IDataProtector dataProtecter = app.CreateDataProtector( typeof(OAuthAuthorizationServerMiddleware).Namespace, "Access_Token", "v1"); Options.AccessTokenFormat = new TicketDataFormat(dataProtecter); } if (Options.RefreshTokenFormat == null) { IDataProtector dataProtecter = app.CreateDataProtector( typeof(OAuthAuthorizationServerMiddleware).Namespace, "Refresh_Token", "v1"); Options.RefreshTokenFormat = new TicketDataFormat(dataProtecter); }