2017-03-02 101 views
1

也許我使用了錯誤的搜索條件,但是我找不到任何有關如何使Aurelia-Authentication與ServiceStack良好搭配的信息。我對網站使用的超級複雜身份驗證方案非常不熟悉,所以如果我嘗試了一些毫無意義的事情,那可能是因爲我很困惑。我試圖做的是讓我的用戶使用他們的Windows憑據登錄,但沒有我的Web應用程序需要IIS進行部署(自我託管)。所以我需要傳輸一個用戶名/密碼,並讓servicestack返回Aurelia可用的內容來存儲經過驗證的會話信息。現在我傾向於使用JWT。Aurelia-Authentication使用自託管服務棧

下面是我在客戶端(Aurelia大街):

main.ts

import { Aurelia } from 'aurelia-framework'; 
import 'src/helpers/exceptionHelpers' 
import config from "./auth-config"; 

export function configure(aurelia: Aurelia) { 
    aurelia.use 
     .standardConfiguration() 
     .feature('src/resources') 
     .developmentLogging() 
     .plugin('aurelia-dialog') 
     .plugin('aurelia-api', config => { 
      // Register an authentication hosts 
      config.registerEndpoint('auth', 'http://localhost:7987/auth/'); 
     }) 
     .plugin('aurelia-authentication', (baseConfig) => { 
      baseConfig.configure(config); 
     }); 

    aurelia.start().then(x => x.setRoot('src/app')); 
} 

AUTH-config.ts

var config = { 
    endpoint: 'auth',    // use 'auth' endpoint for the auth server 
    configureEndpoints: ['auth'], // add Authorization header to 'auth' endpoint 

    // The API specifies that new users register at the POST /users enpoint 
    signupUrl: null, 
    // The API endpoint used in profile requests (inc. `find/get` and `update`) 
    profileUrl: null, 
    // Logins happen at the POST /sessions/create endpoint 
    loginUrl: '', 
    // The API serves its tokens with a key of id_token which differs from 
    // aurelia-auth's standard 
    accessTokenName: 'BearerToken', 
    // Once logged in, we want to redirect the user to the welcome view 
    loginRedirect: '#/pending', 
    // The SPA url to which the user is redirected after a successful logout 
    logoutRedirect: '#/login', 
    // The SPA route used when an unauthenticated user tries to access an SPA page that requires authentication 
    loginRoute : '#/help' 
}; 

export default config; 

login.ts

import { AuthService } from 'aurelia-authentication'; 
import { inject, computedFrom } from 'aurelia-framework'; 

@inject(AuthService) 
export class Login { 
    heading: string; 
    auth: AuthService; 
    userName: string; 
    password: string; 

    constructor(authService) { 
     this.auth = authService; 
     this.heading = 'Login'; 
    } 

    login() { 
     var credentials = { 
      username: this.userName, 
      password: this.password, 
      grant_type: "password" 
     }; 
     return this.auth.login(credentials, 
           { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } 
     ).then(response => { 
       console.log("success logged " + response); 
      }) 
      .catch(err => { 
       console.log("login failure"); 
      }); 
    }; 
} 

AppHost上的配置(se rviceStack):

public override void Configure(Container container) 
    { 
     var privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); 
     var publicKey = privateKey.ToPublicRsaParameters(); 
     var privateKeyXml = privateKey.ToPrivateKeyXml(); 
     var publicKeyXml = privateKey.ToPublicKeyXml(); 

     SetConfig(new HostConfig 
     { 
#if DEBUG 
      DebugMode = true, 
      WebHostPhysicalPath = Path.GetFullPath(Path.Combine("~".MapServerPath(), "..", "..")), 
#endif 
     }); 
     container.RegisterAs<LDAPAuthProvider, IAuthProvider>(); 
     container.Register<ICacheClient>(new MemoryCacheClient { FlushOnDispose = false }); 
     container.RegisterAs<MemoryCacheClient, ICacheClient>(); 
     Plugins.Add(new AuthFeature(() => new AuthUserSession(), 
      new[] { 
       container.Resolve<IAuthProvider>(), 
       new JwtAuthProvider { 
         HashAlgorithm = "RS256", 
         PrivateKeyXml = privateKeyXml, 
         RequireSecureConnection = false, 
        } 
      }) 
     { 
      HtmlRedirect = "~/#/pending", 
      IncludeRegistrationService = false, 
      IncludeAssignRoleServices = false, 
      MaxLoginAttempts = Settings.Default.MaxLoginAttempts 
     }); 
    } 

我有ServiceInterface上的Authenticate屬性我想限制訪問。

最後LDAP提供:

public class LDAPAuthProvider : CredentialsAuthProvider 
{ 
    private readonly IHoldingsManagerSettings _settings; 

    public LDAPAuthProvider(IHoldingsManagerSettings settings) 
    { 
     _settings = settings; 
    } 
    public override bool TryAuthenticate(IServiceBase authService, string userName, string password) 
    { 
     //Check to see if the username/password combo is valid, an exception will be thrown if the username or password is wrong 
     try 
     { 
      var entry = new DirectoryEntry($"LDAP://{_settings.Domain}", userName, password); 
      var nativeObject = entry.NativeObject; 
      using (var identity = new WindowsIdentity(userName)) 
      { 
       var principal = new WindowsPrincipal(identity); 
       return principal.IsInRole(_settings.AdminGroupName); 
      } 
     } 
     catch (Exception) 
     { 
      //This means the username/password combo failed 
      return false; 
     } 
    } 

    public override IHttpResult OnAuthenticated(IServiceBase authService, 
               IAuthSession session, 
               IAuthTokens tokens, 
               Dictionary<string, string> authInfo) 
    { 
     //Fill IAuthSession with data you want to retrieve in the app eg: 
     session.DisplayName = "Testy McTesterson"; 
     //... 

     //Call base method to Save Session and fire Auth/Session callbacks: 
     return base.OnAuthenticated(authService, session, tokens, authInfo); 

     //Alternatively avoid built-in behavior and explicitly save session with 
     //authService.SaveSession(session, SessionExpiry); 
     //return null; 
    } 
} 

到目前爲止,當我嘗試登錄我設法讓儘可能ServiceStack接收LDAP提供的請求,認證成功,但是當請求到來back aurelia-authentication不喜歡任何ServiceStack在會話信息中返回的格式。

我當然不會理解這裏發生的事情。如果有人能指引我如何繼續我的正確方向,我會非常感激。

編輯1

改變了 'accessTokenName' 到 'BearerToken',似乎至少得到了有效載荷集。但仍然在客戶端獲得失敗的身份驗證。還需要弄清楚如何讓Aurelia-Authentication將會話存儲在cookie中。

編輯2

許多調試後,似乎一切正常,問題是,後登錄成功,我重定向到一個頁面,使得必須進行身份驗證的呼叫。但是我在使用的servicestack JsonServiceClient經過驗證的智威湯遜令牌的問題,在這裏看到: ServiceStack Javascript JsonServiceClient missing properties

回答

1

原來上面LDAPprovider將無法正常工作,當你部署到生產環境超出了這個線程的範圍(原因你希望的方式)。

如果您包含對System.DirectoryServices的引用。AccountManagement

,並更改下面的方法:

public override bool TryAuthenticate(IServiceBase authService, string userName, string password) 
{ 
    //Check to see if the username/password combo is valid, an exception will be thrown if the username or password is wrong 
    try 
    { 
     var entry = new DirectoryEntry($"LDAP://{_settings.Domain}", userName, password); 
     var nativeObject = entry.NativeObject; 

     var ctx = new PrincipalContext(ContextType.Domain, _settings.Domain); 
     var user = UserPrincipal.FindByIdentity(ctx, userName); 
     if (user == null) 
     { 
      return false; 
     } 

     var group = GroupPrincipal.FindByIdentity(ctx, _settings.AdminGroupName); 
     if (group == null) 
     { 
      return false; 
     } 

     return user.IsMemberOf(group); 
    } 
    catch (Exception) 
    { 
     //This means the username/password combo failed 
     return false; 
    } 
} 

一切都應該按預期工作。