简体   繁体   English

Angular 2 / .NET Core-授权的内容预渲染

[英]Angular 2/.NET core - authorized content prerendering

I am trying to implement authentication/authorization on Angular 2 and .net core (kicked off with this: https://github.com/aspnet/JavaScriptServices ) 我正在尝试在Angular 2和.net核心上实现身份验证/授权(已通过以下方式启动: https : //github.com/aspnet/JavaScriptServices

What Is my storage options for auth token (jwt) - so it could be accessible?: 我的身份验证令牌(jwt)的存储选项是什么-因此可以访问?

  • From client: write on login and when needed to renew the token, read when making get/post requests 从客户端:在登录时写以及何时需要更新令牌,在进行获取/发布请求时阅读
  • From server: read when node is prerendering the app (same requests, but from node context) 从服务器:读取节点何时预渲染应用程序(相同请求,但来自节点上下文)

I understand that there is no much point to prerender protected content - since it won't be indexed anyways - but this brings the flickering issue back. 我知道预渲染受保护的内容没有太多意义-因为无论如何都不会对其进行索引-但这又使闪烁的问题再次出现。 Since node can not access this token (in my scenario) - server returns content-less html (in case the content requires authorization) 由于节点无法访问此令牌(在我的情况下)-服务器返回无内容的html(以防内容需要授权)

Currently I store my token in browser's local storage: 目前,我将令牌存储在浏览器的本地存储中:

localStorage.setItem('currentUser', JSON.stringify({ username: username, token: token }));

... obviously node has no such thing and can not access it ... ...显然,节点没有这种东西,无法访问...

Simple get request: 简单获取请求:

let headers = new Headers({ 'Authorization': 'Bearer ' + this.authenticationService.token });
let options = new RequestOptions({ headers: headers });
this.http.get(url, options).subscribe(response => callback(<any>response));

I am really early on learning/adopting this - I would also consider any other auth methods, but it has to comply with rule to be able to prerender authorized content. 我真的很早就开始学习/采用此方法-我还会考虑其他身份验证方法,但是它必须符合规则才能呈现授权内容。

I was able to solve this by using cookie as a token storage and then passing the token from cookie to asp-prerender-module. 我可以通过使用cookie作为令牌存储来解决此问题,然后将令牌从cookie传递给asp-prerender-module。

Storage service for client and server: 客户端和服务器的存储服务:

declare var tokenStorage: NodeTokenStorage;    

@Injectable()
export class TokenStorageService implements NodeTokenStorage {

    getItem(key: string): string {
        if (!isBrowser) {
            return tokenStorage.getItem(key);
        }
        else {
            return getCookie(key);
        }
    }

    setItem(key: string, value: string): void {
        if (!isBrowser) {
            tokenStorage.setItem(key, value);
        }
        else {
            setCookie(key, value, 1);
        }
    }

    removeItem(key: string): void {
        if (!isBrowser) {
            tokenStorage.removeItem(key);
        }
        else {
            removeCookie(key);
        }
    }
}

interface NodeTokenStorage {
    getItem(key: string): string;
    setItem(key: string, value: string): void;
    removeItem(key: string): void;
}

Inject the cookie to prerender module: 将cookie注入到prerender模块中:

<app
     asp-prerender-module="ClientApp/dist/main-server"
     asp-prerender-data='new { token = Context.Request.Cookies["token"] }'>
    Loading...
</app>

Read it the following way (ClientApp/boot-server.ts): 通过以下方式阅读它(ClientApp / boot-server.ts):

(global as any).tokenStorage = {
    getItem: function(key) {
        return this[key];
    },
    setItem: function (key, value) {
        this[key] = value;
    },
    removeItem: function(key) {
        this[key] = undefined;
    }
}

export default createServerRenderer(params => {

    (global as any).tokenStorage.setItem('token', params.data.token);

    return new Promise<RenderResult>((resolve, reject) => {
        const requestZone = Zone.current.fork({
            name: 'angular-universal request',
            properties: {
                baseUrl: '/',
                requestUrl: params.url,
                originUrl: params.origin,
                preboot: false,
                document: '<app></app>'
            },
            onHandleError: (parentZone, currentZone, targetZone, error) => {
                // If any error occurs while rendering the module, reject the whole operation
                reject(error);
                return true;
            }
        });

        return requestZone.run<Promise<string>>(() => platform.serializeModule(AppModule)).then(html => {
            resolve({ html: html });
        }, reject);
    });
});

Then - when app starts (before routing and redux store setup on a server side): I would read the token to get necessary data for authenticated user. 然后-当应用启动时(在服务器端进行路由和Redux存储设置之前):我将读取令牌以获取经过身份验证的用户所需的数据。 This way complete html comes back from server including all the auth content and user-specific data. 这样,完整的html从服务器返回,包括所有身份验证内容和特定于用户的数据。

refs: https://github.com/aspnet/JavaScriptServices/tree/dev/src/Microsoft.AspNetCore.SpaServices#server-side-prerendering 裁判: https : //github.com/aspnet/JavaScriptServices/tree/dev/src/Microsoft.AspNetCore.SpaServices#server-side-prerendering

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM