首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Aurelia-使用自托管服务栈进行身份验证

Aurelia-使用自托管服务栈进行身份验证
EN

Stack Overflow用户
提问于 2017-03-02 21:55:05
回答 1查看 260关注 0票数 1

也许我使用了错误的搜索词,但是我找不到任何关于如何让Authentication与ServiceStack友好相处的信息。我对网站使用的超级复杂的身份验证方案非常陌生,所以如果我在尝试一些没有意义的东西,那可能是因为我很困惑。我想要做的是允许我的用户使用他们的windows凭据登录,但是我的web应用程序不需要IIS进行部署(自我托管)。因此,我需要传输用户名/密码,并让servicestack返回一些可由Aurelia使用的内容来存储经过身份验证的会话信息。现在,我倾向于使用JWT。

下面是我在客户端(Aurelia)所拥有的内容:

main.ts

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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 (ServiceStack)上的配置:

代码语言:javascript
复制
    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上有身份验证属性。

最后,LDAP提供程序:

代码语言:javascript
复制
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提供程序中的请求时,身份验证成功了,但是当请求返回时,aurelia身份验证不喜欢ServiceStack在它的会话信息中返回的任何格式。

我对这里所发生的事情的理解肯定离我很远。如果有人能为我指明前进的方向,我会非常感激的。

编辑1

将“accessTokenName”改为“BearerToken”,似乎至少得到了有效负载集。但仍然在客户端获得失败的身份验证。还需要弄清楚如何获得Authentication,以便将会话存储在cookie中。

编辑2

经过大量调试后,似乎一切都正常工作,问题是在登录成功后,我被重定向到一个必须进行身份验证的调用的页面。但是,我在使用servicestack JsonServiceClient传递经过身份验证的Jwt令牌时遇到了问题,请参阅此处:ServiceStack Javascript JsonServiceClient missing properties

EN

回答 1

Stack Overflow用户

发布于 2017-03-10 20:54:20

原来,当您部署到生产中时,上面的LDAPprovider不会像您期望的那样工作(原因超出了这个线程的范围)。

如果包含对: System.DirectoryServices.AccountManagement的引用

并更改以下方法:

代码语言:javascript
复制
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;
    }
}

一切都应如预期的那样运作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42566745

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档