bixi
Version:
企业级中后台前端解决方案
145 lines (128 loc) • 4.15 kB
text/typescript
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, Observer } from 'rxjs';
import { BIXI_SERVICE_TOKEN, ITokenModel, ITokenService } from '../token/interface';
const OPENTYPE = '_bixiAuthSocialType';
const HREFCALLBACK = '_bixiAuthSocialCallbackByHref';
export type SocialOpenType = 'href' | 'window';
()
export class SocialService implements OnDestroy {
private _win: Window | null;
// tslint:disable-next-line:no-any
private _winTime: any;
private observer: Observer<ITokenModel | null>;
constructor(
(BIXI_SERVICE_TOKEN) private tokenService: ITokenService,
// tslint:disable-next-line:no-any
(DOCUMENT) private doc: any,
private router: Router
) {
}
/**
* 使用窗体打开授权页,返回值是 `Observable<ITokenModel>` 用于订阅授权后返回的结果
* @param url 获取授权地址
* @param callback 回调路由地址
* @param options options.windowFeatures 等同 `window.open` 的 `features` 参数值
*/
login(
url: string,
callback?: string,
options?: {
type?: 'window';
windowFeatures?: string;
}
): Observable<ITokenModel>;
/**
* 跳转至授权页
* @param url 获取授权地址
* @param callback 回调路由地址
* @param options type
*/
login(
url: string,
callback?: string,
options?: {
type?: 'href';
}
): void;
/**
* 跳转至登录页,若为 `type=window` 时,返回值是 `Observable<ITokenModel>`
* @param url 获取授权地址
* @param callback 当 `type=href` 成功时的回调路由地址
* @param options options.type 打开方式,默认 `window` options.windowFeatures 等同 `window.open` 的 `features` 参数值
*/
login(
url: string,
callback: string = '/',
options: {
type?: SocialOpenType;
windowFeatures?: string;
} = {}
): Observable<ITokenModel | null> | void {
options = {
type: 'window',
windowFeatures: 'location=yes,height=570,width=520,scrollbars=yes,status=yes',
...options
};
// tslint:disable-next-line:no-non-null-assertion
localStorage.setItem(OPENTYPE, options.type!);
localStorage.setItem(HREFCALLBACK, callback);
if (options.type === 'href') {
this.doc.location.href = url;
return;
}
this._win = window.open(url, '_blank', options.windowFeatures);
this._winTime = setInterval(() => {
if (this._win && this._win.closed) {
this.ngOnDestroy();
let model = this.tokenService.get();
if (model && !model.token) model = null;
// 触发变更通知
if (model) {
this.tokenService.set(model);
}
this.observer.next(model);
this.observer.complete();
}
}, 100);
return new Observable((observer: Observer<ITokenModel | null>) => {
this.observer = observer;
});
}
/**
* 授权成功后的回调处理
*
* @param rawData 指定回调认证信息,为空时从根据当前URL解析
*/
callback(rawData?: ITokenModel | string | null): ITokenModel {
// from uri
if (!rawData && this.router.url.indexOf('?') === -1) {
throw new Error(`url muse contain a ?`);
}
// parse
let data: ITokenModel = { token: `` };
if (typeof rawData === 'string') {
const rightUrl = rawData.split('?')[1].split('#')[0];
data = this.router.parseUrl('./?' + rightUrl).queryParams as ITokenModel;
} else {
data = rawData as ITokenModel;
}
if (!data || !data.token) throw new Error(`invalide token data`);
this.tokenService.set(data);
const url = localStorage.getItem(HREFCALLBACK) || '/';
localStorage.removeItem(HREFCALLBACK);
const type = localStorage.getItem(OPENTYPE);
localStorage.removeItem(OPENTYPE);
if (type === 'window') {
window.close();
} else {
this.router.navigateByUrl(url);
}
return data;
}
ngOnDestroy(): void {
clearInterval(this._winTime);
this._winTime = null;
}
}