Aurelia-Authentication使用自托管服务栈
也许我使用了错误的搜索条件,但是我找不到任何有关如何使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
原来上面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;
}
}
一切都应该按预期工作。