Open rony2818 opened 4 years ago
import { ContractKbn } from '@/utils/constants';
export interface LoginUser {
companycode: string;
userid: string;
usercode: string;
username: string;
usermail: string;
departmentcodes: string[];
department?: {
departmentCd: string;
departmentNm: string;
};
subDepartmentcodes: string[][];
authorities: Array<{ authority: string }>;
adminFlg: boolean;
locale: string;
contractKbn?: ContractKbn;
tenantCd: string;
notInitializeFlg: boolean;
notLoginFlg: boolean;
countDateTrial: number;
zendeskSubdomain: string;
zendeskJwt: string;
zendeskWidgetKey: string;
slackClientId: string;
introduction?: {
globalMenuFlg: boolean;
checkinFlg: boolean;
};
_csrf: string;
}
interface SimpleUserInfo {
tenantId: string;
employeeId: string;
systemDate?: string;
}
/**
* 正常終了のステータスかどうかをチェックします。
*
* @param status ステータス
* @return true:正常、false:異常
*/
export const isValidStatus = (status: number): boolean => {
return status >= 200 && status < 300; // axios default
};
/**
* Get login user's information.
*
* @param disableErrorHandler true:disable error handler, false:default
* @return Promise
*/
const findUserInformation = (disableErrorHandler: boolean): Promise<LoginUser> => {
return axios
.get('/auth/userInfo', {
validateStatus(status: number): boolean {
// https://github.com/mzabriskie/axios#handling-errors
if (disableErrorHandler) {
return true; // axios-exのエラーハンドラーを無効化するため、全てのステータスを正常系扱いにする
} else {
return isValidStatus(status);
}
}
})
.then(response => {
if (isValidStatus(response.status)) {
return response.data;
} else {
return Promise.reject(response);
}
});
};
/**
* ログイン認証を行います。
*
* @param data ログイン情報
* @return Promise
*/
const login = (data: {
tenantCd: string;
employeeMail: string;
password: string;
saveCredentials: boolean;
}): Promise<LoginUser> => {
const params = new URLSearchParams();
params.append('tenantcd', data.tenantCd);
params.append('employeemail', data.employeeMail);
params.append('password', data.password);
params.append('savecredentials', data.saveCredentials + '');
return axios
.post('/auth/login/confirm', params, {
validateStatus(status: number): boolean {
// https://github.com/mzabriskie/axios#handling-errors
return isValidStatus(status) || status === 401; // axios-exのエラーハンドラーを無効化するため、401を正常系扱いにする
}
})
.then(response => {
if (response.status === 401) {
// 401を正常終了で受け取った後、サービスとしては異常終了とする
return Promise.reject(response);
} else {
return response.data;
}
});
};
/**
* ログアウトを行います。
*
* @return Promise
*/
const logout = (): Promise<string> => {
return axios.post('/auth/logout').then(response => {
return response.data;
});
};
/**
* ユーザのログイン情報を取得します。
*/
const bindLoginCredentials = (): Promise<{ tenantCd: string; employeeMail: string; saveCredentials: boolean }> => {
return axios.get('/auth/credentials').then(response => {
return response.data;
});
};
/**
* メールアドレス検索し、検索結果のメールアドレスにメール送信します。
*/
const sendPasswordResetEmail = (credentials: { tenantCd: string; employeeMail: string }): Promise<void> => {
return axios.post('/auth/sendMail', credentials).then(response => {
return response.data;
});
};
// /**
// * テナントIDとURLハッシュ検索し、検索結果のユーザーにパスワード再設定画面を表示する。
// *
// * @param data 社員データオブジェクト
// * @param data.employeeMail メールアドレス
// * @param data.tenantId テナントID
// * @return Promise
// */
// export function authenticateUrl(data) {
// return axios.post('/auth/sendMail/url', data).then(response => {
// return response.data;
// });
// }
/**
* 新規パスワードを設定します。
*/
const modifyPassword = (data: { password: string; tenantCd: string; urlHash: string }): Promise<void> => {
return axios.post('/auth/password/modify', data).then(response => {
return response.data;
});
};
// /**
// * 管理者情報の初期設定を行います。
// *
// * @param data 管理者情報オブジェクト
// * @return Promise
// */
// export function initialize(data) {
// return axios.post('/auth/initialize', data).then(response => {
// return response.data;
// });
// }
/**
* Get login url environment
*
* @param tenantCd テナントCD
* @return Promise
*/
const searchLoginEnvironment = (tenantCd: string): Promise<string> => {
return axios.get('/auth/loginEnvironment', { params: { tenantCd } }).then(response => {
return response.data;
});
};
/**
* Generate zendesk Jwt
*
* @return {Promise.<String>} jwt
*/
const generateZendeskJwt = (): Promise<string> => {
return axios.get('/auth/generateZendeskJwt').then(response => {
return response.data;
});
};
/**
* Check if session is alive
*
* @param params params
* @return {Promise.<Object>}
*/
const findSimpleUserInformation = (
tenantId: string,
employeeId: string,
date?: string
): Promise<Partial<SimpleUserInfo>> => {
return axios.post(`/auth/simpleUserInfo/${tenantId}/${employeeId}`, { date }).then(response => {
return Object.entries(response.data).reduce((acc, [key, val]) => (val ? { [key]: val, ...acc } : acc), {});
});
};
export default {
findUserInformation,
login,
logout,
bindLoginCredentials,
sendPasswordResetEmail,
// authenticateUrl
modifyPassword,
// initialize
searchLoginEnvironment,
generateZendeskJwt,
findSimpleUserInformation
};
import { Base, Coin, CoinComment, Page, RegisterCoin, RegisterCoinComment } from '@/service/interfaces';
import axios from '@/utils/axios-ex';
export interface CoinReaction extends Partial<Base> {
coinReactionId: string;
coinId: string;
employeeId: string;
}
export interface CoinDetail {
coinDetails: {
coinsReceived: Coin[];
coinsSent: Coin[];
};
}
/**
* Send coin to employees
*
* @param coinInfo coin's information
* @return Promise
*/
const sendCoinToEmployees = (coinInfo: RegisterCoin): Promise<Coin> => {
return axios.post('/coin', coinInfo).then(response => {
return response.data;
});
};
// /**
// * Search coins summary for department
// *
// * @param departmentCds department codes
// * @return Promise
// */
// const searchDepartmentCoins = (departmentCds: string[]): Promise<Page<Coin>> => {
// const params = {
// departmentCds
// };
// return axios
// .get('/coin', {
// params
// })
// .then(response => {
// return response.data;
// });
// };
// /**
// * Search coins summary for employees
// *
// * @param employeeIds 社員ID
// * @return Promise
// */
// const searchSummary = (employeeIds: string[]): Promise<Page<Coin>> => {
// const params = {
// employeeIds
// };
// return axios
// .get('/coin', {
// params
// })
// .then(response => {
// return response.data;
// });
// };
/**
* Search coins detail for employee.
*
* @param employeeId employee id
* @param fromDate Date
* @param toDate Date
* @return Promise
*/
const searchDetail = (employeeId = '', fromDate?: string, toDate?: string): Promise<CoinDetail> => {
const params = {
employeeId,
fromDate,
toDate
};
return axios
.get('/coin/detail', {
params
})
.then(response => {
return response.data;
});
};
/**
* コインIDからコインを取得します。
*
* @param coinId コインID
* @return 取得結果
*/
const searchDetailByCoinId = (coinId: string): Promise<Coin> => {
return axios.get(`/coin/${coinId}`).then(response => {
return response.data;
});
};
// /**
// * Select Coin Report By DepartmentCd And Date.
// *
// * @param departmentCd departmentCd
// * @param fromDate Date
// * @param toDate Date
// * @return Promise
// */
// const searchCoinReport = (departmentCd: string, fromDate: Date, toDate: Date): Promise<Page<Coin>> => {
// const params = {};
// if (!_.isEmpty(departmentCd)) {
// params.departmentCd = departmentCd;
// }
// if (!_.isEmpty(fromDate)) {
// params.fromDate = fromDate;
// }
// if (!_.isEmpty(toDate)) {
// params.toDate = toDate;
// }
// return axios
// .get('/coin/report', {
// params
// })
// .then(response => {
// return response.data.content;
// });
// };
/**
* Remove coin info
*
* @param coinId Coin id
* @return Promise
*/
const removeCoin = (coinId: string): Promise<Coin> => {
return axios.delete(`/coin/${coinId}`).then(response => {
return response.data;
});
};
/**
* Edit coin info
*
* @param coinId Coin id
* @param coin coin's information
* @return Promise
*/
const modifySentCoin = (coinId: string, coin: Coin): Promise<Coin> => {
return axios.post(`/coin/${coinId}`, coin).then(response => {
return response.data;
});
};
/**
* 指定したコイン反応に紐付く社員情報を取得します。
*
* @param coinId コインID
* @return 取得結果
*/
const searchReactionEmployee = (
coinId: string
): Promise<Page<{ employeeId: string; employeeLastNm: string; employeeFirstNm: string }>> => {
return axios.get(`/coin/${coinId}/reaction`).then(response => {
return response.data;
});
};
/**
* コイン反応を登録します。
*
* @param coinId コインID
* @return 登録結果
*/
const registerReaction = (coinId: string): Promise<CoinReaction> => {
return axios.post(`/coin/${coinId}/reaction`).then(response => {
return response.data;
});
};
/**
* コイン反応を削除します。
*
* @param coinId コインID
* @param employeeId 社員ID
* @return 削除結果
*/
const removeReaction = (coinId: string): Promise<CoinReaction> => {
return axios.delete(`/coin/${coinId}/reaction`).then(response => {
return response.data;
});
};
/**
* コインコメントを登録します。
*
* @param coinId コインID
* @param coinComment コインコメントの情報を保持するオブジェクト
* @return 登録結果
*/
const registerComment = (coinId: string, coinComment: RegisterCoinComment): Promise<CoinComment> => {
return axios.post(`/coin/${coinId}/comment`, coinComment).then(response => {
return response.data;
});
};
// /**
// * コインコメントを更新します。
// *
// * @param coinId コインID
// * @param coinCommentId コインコメントID
// * @param coinComment コインコメントの情報を保持するオブジェクト
// * @return 登録結果
// */
// const modifyComment = (coinId: string, coinCommentId: string, coinComment: CoinComment): Promise<CoinComment> => {
// return axios.post(`/coin/${coinId}/comment/${coinCommentId}`, coinComment).then(response => {
// return response.data;
// });
// };
/**
* コインコメントを削除します。
*
* @param coinId コインID
* @param coinCommentId コインコメントID
* @return 削除結果
*/
const removeComment = (coinId: string, coinCommentId: string): Promise<CoinComment> => {
return axios.delete(`/coin/${coinId}/comment/${coinCommentId}`).then(response => {
return response.data;
});
};
export default {
sendCoinToEmployees,
// searchDepartmentCoins,
searchDetailByCoinId,
// searchSummary,
searchDetail,
// searchCoinReport,
removeCoin,
modifySentCoin,
searchReactionEmployee,
registerReaction,
removeReaction,
registerComment,
// modifyComment,
removeComment
};```
export interface Page<T> {
content: T[];
first: boolean;
last: boolean;
number: number;
numberOfElements: number;
size: number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
sort: any;
totalElements: number;
totalPages: number;
}
export interface Base {
insertDateTime: string;
updateDateTime: string;
versionNo: number;
}
export interface BaseCoin extends Partial<Base> {
senderId: string;
type: CoinType;
privateFlg: 0 | 1;
message: string;
}
export interface Coin extends BaseCoin {
coinId: string;
receivers: string[];
}
export interface RegisterCoin extends BaseCoin {
receiverEmployeeIds: string[];
}
export interface CoinComment extends Partial<Base> {
coinCommentId: string;
coinId: string;
employeeId: string;
privateFlg: boolean;
comment: string;
}
export interface RegisterCoinComment {
privateFlg: boolean;
comment: string;
}
export interface Department {
departmentId: string;
departmentCd: string;
departmentNm: string;
}
export interface Employee {
basic: {
employeeId: string;
employeeCd: string;
employeeFullNm: string;
};
belongingInformation: Array<{
belonging: string;
currentFlg: boolean;
}>;
}
import _ from 'lodash';
import Vue from 'vue';
import { Route } from 'vue-router';
import customFilters from '@/custom-filters';
import customMethods from '@/plugins/methods';
import veeValidate from '@/plugins/vee-validate';
import { LoginRouteName, RouteName as PermittedRoute } from '@/router/permitted-route';
import { RouteName as SlackRoute } from '@/router/slack-route';
import authService from '@/service/auth-service';
import { Action as AuthAction, AuthState, Getter as AuthGetter, LoginUser } from '@/store/modules/auth/types';
import { Action as CacheAction, EmployeeItemTab, Getter as CacheGetter } from '@/store/modules/cache/types';
import { Action, Mutation as RootMutation } from '@/store/types';
import { AxiosErrorEx, helpers } from '@/utils/axios-ex';
import * as stringUtil from '@/utils/string-util';
const DISABLE_LOADING_URLS = ['/functionLock/lock', '/auth/simpleUserInfo'];
export default class MainVue extends Vue {
public lastConnectionDateTime?: string;
public requestResolvers: Array<() => void> = [];
public requestRejecters: Array<() => void> = [];
public get loginUser(): LoginUser {
return (this.$store.state.auth as AuthState).loginUser;
}
public get loginDialogState(): { action: 'resolve' | 'reject' | 'none'; isOpen: boolean } {
return this.$store.state.loginDialog;
}
public get message(): { [index: string]: string } {
return this.$store.getters[`cache/${CacheGetter.Message}`];
}
public get multilingual(): { [index: string]: string } {
return this.$store.getters[`cache/${CacheGetter.Multilingual}`];
}
public get isLoggedIn(): boolean {
return this.$store.getters[`auth/${AuthGetter.LoggedInFlg}`];
}
public get employeeItemSettings(): EmployeeItemTab[] {
return this.$store.getters[`cache/${CacheGetter.EmployeeItemSettings}`];
}
public get title(): string {
const title = `${_.get(
this.multilingual,
_.get(this.currentRoute, 'meta.titleKey'),
_.get(this.currentRoute, 'meta.title', '')
)}`;
const suffix = `${_.get(this.multilingual, 'pageTitleSuffix', '- パフォーマンス -')}`;
return `${title} ${suffix}`;
}
public get currentRoute(): Route {
// When app is created, current route is root route,
// actual route (the route that match location) is pending
return this.$router.history.pending || this.$route;
}
public hasAuthority(functionCds: string | string[]): boolean {
return this.$store.getters[`auth/${AuthGetter.HasAuthority}`](functionCds);
}
public findEnvironmentKbn(): Promise<void> {
return this.$store.dispatch(Action.FindEnvironmentKbn);
}
public synchronizeMessage(): Promise<void> {
return this.$store.dispatch(`cache/${CacheAction.SynchronizeMessage}`);
}
public synchronizeMultilingual(): Promise<void> {
return this.$store.dispatch(`cache/${CacheAction.SynchronizeMultilingual}`);
}
public synchronizeCode(): Promise<void> {
return this.$store.dispatch(`cache/${CacheAction.SynchronizeCode}`);
}
public synchronizeItems(): Promise<void> {
return this.$store.dispatch(`cache/${CacheAction.SynchronizeEmployeeItemData}`);
}
public findUserInformation(params: { ignoreError: true }): Promise<void> {
return this.$store.dispatch(`auth/${AuthAction.FindUserInformation}`, params);
}
public setRestError(error: AxiosErrorEx): void {
this.$store.commit(`${RootMutation.SetRestError}`, error);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public setError(error: any): void {
this.$store.commit(`${RootMutation.SetError}`, error);
}
public clearError(): void {
this.$store.commit(`${RootMutation.ClearError}`);
}
public setLoginDialogState({ action, isOpen }: { action?: 'resolve' | 'reject' | 'none'; isOpen?: boolean }): void {
this.$store.commit(`${RootMutation.SetLoginDialogState}`, { action, isOpen });
}
// ...mapMutations('userSetting', {
// initUserSetting: types.userSetting.mutations.INIT_SETTING
// })
public checkRouteAuthority(to: Route): boolean {
const requiredAuthorities = _.get(to, 'meta.authorities', []);
if (this.hasAuthority(requiredAuthorities)) {
return true;
}
this.setError({ errorTitle: 'Forbidden', errorMessage: this.message.EKITEZ2002, status: 403 });
return false;
}
public synchronizeCache(): Promise<void[]> {
const promises = [];
promises.push(this.synchronizeMessage());
promises.push(this.synchronizeMultilingual());
if (this.isLoggedIn) {
promises.push(this.synchronizeCode());
promises.push(this.synchronizeItems());
}
return Promise.all(promises);
}
public resolveAndClear(action: 'resolve' | 'reject'): void {
if (action === 'resolve') {
this.requestResolvers.forEach(resolve => resolve());
} else {
this.requestRejecters.forEach(reject => reject());
}
this.requestResolvers = [];
this.requestRejecters = [];
}
public isLoaderRequest(requestConfig?: AxiosRequestConfig): boolean {
// リクエストをキャンセルすると requestConfig は undefined となる(再ログインダイアログを表示し、ログインせずログアウトした場合)
if (requestConfig === undefined) {
return false;
}
const requestUrl = requestConfig.url || '';
const baseURL = requestConfig.baseURL || '';
const relativeUrl = requestUrl.replace(baseURL, '');
return !DISABLE_LOADING_URLS.find(url => relativeUrl.includes(url));
}
public restErrorHandler(error: AxiosErrorEx): void {
const response = error.response;
if (response && [400, 409, 413].includes(response.status)) {
this.$snackbar.hideAll();
const defaultMessage = this.message.EKITEZ1001 || '入力パラメータに誤りがあるため処理できません。'; // アノテーションでバリデーションエラーが発生した場合はこれが適用される
const rowMessage = this.message.EKITEZ1152 || '{0}行:{1}'; // 複数行エラーメッセージ
if (response.data.completeInfo) {
const details = response.data.completeInfo.details;
const messages = details.map(detail =>
detail.row ? stringUtil.format(rowMessage, detail.row, detail.message) : detail.message
);
this.$snackbar.error(messages);
} else {
this.$snackbar.error(defaultMessage);
}
} else {
if (error instanceof axios.Cancel) {
this.$router.push({ name: PermittedRoute.Logout, params: { logoutFlg: true + '', force: true + '' } }); // force: true でナビゲーションガードを無効にします
} else {
this.setRestError(error);
this.$router.push({ name: PermittedRoute.Error });
}
}
}
public async restPreProcess(requestConfig: AxiosRequestConfig): Promise<AxiosRequestConfig> {
if (this.isLoaderRequest(requestConfig)) {
if (requestConfig.method && requestConfig.method.toUpperCase() === 'POST') {
this.$loader.show();
} else {
this.$loader.showProgress();
}
}
const { baseURL, url } = requestConfig;
const isAuthRequest = `${baseURL}${url}`.includes(`${baseURL}/auth/`);
if (this.isLoggedIn && !isAuthRequest) {
try {
const { tenantId, employeeId, systemDate } = await authService.findSimpleUserInformation(
this.loginUser.tenantId,
this.loginUser.employeeId,
this.lastConnectionDateTime
);
this.lastConnectionDateTime = systemDate;
if (!tenantId && !employeeId) {
if (!this.loginDialogState.isOpen) {
this.setLoginDialogState({ isOpen: true });
}
await new Promise((resolve, reject) => {
this.requestResolvers = [...this.requestResolvers, resolve];
this.requestRejecters = [...this.requestRejecters, reject];
});
}
} catch (error) {
helpers.cancel(error);
}
}
return requestConfig;
}
public restPostProcess(response: AxiosResponse): void {
if (this.isLoaderRequest(response.config)) {
if (response.config.method && response.config.method.toUpperCase() === 'POST') {
this.$loader.hide();
} else {
this.$loader.hideProgress();
}
}
}
/**
* 初期表示のURLや認証状態に応じてログイン画面へ遷移します。
*
* @returns 初期表示のURLがログイン画面でなく、ログイン画面へ遷移した場合は true を返却する
*/
public redirectToLogin(): boolean {
if (this.isLoggedIn) {
return false;
}
// ログイン画面へアクセスした場合、UserAgentを判別しPC・モバイルの適切なログイン画面へ遷移する
if (this.currentRoute.name === LoginRouteName.Default || this.currentRoute.name === LoginRouteName.Mobile) {
this.$router.push({ name: PermittedRoute.Login });
return false;
}
// ログイン画面を除いて、認証前でもアクセスできる画面では何もしない
const permittedPaths = [
PermittedRoute.Root,
PermittedRoute.Logout,
PermittedRoute.Error,
PermittedRoute.ForgotPassword,
PermittedRoute.ResetPassword,
// PermittedRoute.SignUp,
PermittedRoute.TenantConfirmation,
SlackRoute.AddToSlack
];
if (permittedPaths.some(path => path === this.currentRoute.name)) {
return false;
}
// 認証しておらず、認証後にアクセスできる画面の場合、ログイン画面へ遷移しつつ、ユーザがアクセスした画面の情報を保持する
this.$router.push({
name: PermittedRoute.Login,
query: { 'return-to': window.location.href.replace(window.location.origin, '') }
});
return true;
}
public onLoginDialogStateChange(): void {
const { action, isOpen } = this.loginDialogState;
if (isOpen === false && (action === 'resolve' || action === 'reject')) {
this.resolveAndClear(action);
this.setLoginDialogState({ action: 'none' });
}
}
public async onCreated(): Promise<void> {
// Restクライアントでエラーが起こった場合の処理を設定
helpers.setErrorHandler(error => {
this.restErrorHandler(error);
});
// リクエスト前処理を設定
helpers.setPreProcess(
(config: AxiosRequestConfig): Promise<AxiosRequestConfig> => {
return this.restPreProcess(config);
}
);
// リクエスト後処理を設定
helpers.setPostProcess(response => {
return this.restPostProcess(response);
});
// ページ遷移前の処理の登録
// ルートマッチ時の共通前処理(グローバルガード)
this.$router.beforeEach(async (to, from, next) => {
if (process.env.NODE_ENV === 'development') {
// eslint-disable-next-line no-console
console.log('[main] $router.beforeEach from', from);
// eslint-disable-next-line no-console
console.log('[main] $router.beforeEach to', to);
}
this.$snackbar.hideAll();
if (!this.checkRouteAuthority(to)) {
if (this.isLoggedIn) {
next({ name: PermittedRoute.Error });
} else {
next({
name: PermittedRoute.Login,
query: { 'return-to': window.location.href.replace(window.location.origin, '') }
});
}
return;
}
if (to.name === PermittedRoute.Logout || to.name === PermittedRoute.Error) {
// ログアウトページ、エラーページへ遷移するときはすぐに遷移する(遷移処理中の想定外エラーを避けるため)
next();
return;
}
// 先頭の'/'を削除する。かつ、モバイル版の場合先頭pathに'm/'が付くため、そのpathも削除する。
// replace処理を行った上で先頭のpathを取得する
const fromPage = from.path.replace(/^\/m?\/?/, '').split('/')[0];
const toPage = to.path.replace(/^\/m?\/?/, '').split('/')[0];
// pages(画面)のルーティングが発生した場合の処理
// '/path1/path1-1' から '/path1/path1-2' へ遷移するときはこの処理はしない
if (fromPage !== toPage) {
// キャッシュ情報を最新化する
await this.synchronizeCache();
// ユーザの設定情報を初期化する
// this.initUserSetting({ employeeItemSettings: this.employeeItemSettings, authorities: this.loginUser.authorities });
next();
} else {
next();
}
});
// ページ遷移後の処理の登録
this.$router.afterEach(to => {
document.title = this.title;
if (to.name !== PermittedRoute.Error) {
// エラーページ以外へ遷移するときは、過去にエラー画面へ遷移したときのエラーキャッシュ情報をクリアする
// (この処理を beforeEach で行うとエラー画面から別画面へ遷移するときに画面がちらつくので、afterEach で行う)
this.clearError();
}
});
const isRedirected = this.redirectToLogin();
await Promise.all([this.findEnvironmentKbn(), this.synchronizeCache()]);
// ログイン画面へ遷移しておらず、権限がない画面へアクセスした場合はエラー画面へ遷移する(エラーメッセージをサーバから取得するため、上記 synchronize の処理より後にする)
if (!isRedirected && !this.checkRouteAuthority(this.currentRoute)) {
this.$router.push({ name: PermittedRoute.Error });
}
customFilters.initFilter(() => this.message, () => this.multilingual);
customMethods.initMethod(() => this.multilingual);
veeValidate.initDictionary(() => this.message);
// 初期表示のタイトルを設定する
document.title = this.title;
// // ユーザの設定情報を初期化する
// this.initUserSetting({ employeeItemSettings: this.employeeItemSettings, authorities: this.loginUser.authorities });
}
}