forked from morrning/hesabixCore
291 lines
9.7 KiB
Vue
291 lines
9.7 KiB
Vue
<template>
|
||
<div class="oauth-authorize-container">
|
||
<v-container class="fill-height">
|
||
<v-row justify="center" align="center">
|
||
<v-col cols="12" sm="8" md="6" lg="4">
|
||
<v-card class="oauth-card" elevation="8">
|
||
<v-card-title class="text-center pa-6">
|
||
<v-icon size="48" color="primary" class="mb-4">mdi-shield-check</v-icon>
|
||
<h2 class="text-h4 font-weight-bold">مجوزدهی OAuth</h2>
|
||
</v-card-title>
|
||
|
||
<v-card-text class="pa-6">
|
||
<!-- Loading State -->
|
||
<div v-if="loading" class="text-center">
|
||
<v-progress-circular indeterminate color="primary" size="64"></v-progress-circular>
|
||
<p class="mt-4 text-body-1">در حال بارگذاری...</p>
|
||
</div>
|
||
|
||
<!-- Error State -->
|
||
<div v-else-if="error" class="text-center">
|
||
<v-icon size="64" color="error" class="mb-4">mdi-alert-circle</v-icon>
|
||
<h3 class="text-h6 text-error mb-2">خطا در مجوزدهی</h3>
|
||
<p class="text-body-1 mb-4">{{ error }}</p>
|
||
<v-btn color="primary" @click="goBack">بازگشت</v-btn>
|
||
</div>
|
||
|
||
<!-- Authorization Form -->
|
||
<div v-else-if="application" class="authorization-form">
|
||
<!-- Application Info -->
|
||
<div class="application-info mb-6">
|
||
<div class="d-flex align-center mb-4">
|
||
<v-avatar size="64" color="primary" class="mr-4">
|
||
<v-icon size="32" color="white">{{ getApplicationIcon() }}</v-icon>
|
||
</v-avatar>
|
||
<div>
|
||
<h3 class="text-h5 font-weight-bold">{{ application.name }}</h3>
|
||
<p class="text-body-2 text-medium-emphasis">{{ application.description }}</p>
|
||
<v-chip size="small" color="info" variant="outlined" class="mt-1">
|
||
{{ application.website }}
|
||
</v-chip>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Scopes -->
|
||
<div class="scopes-section mb-6">
|
||
<h4 class="text-h6 font-weight-bold mb-3">این برنامه درخواست دسترسی به:</h4>
|
||
<v-list class="scopes-list">
|
||
<v-list-item v-for="scope in scopes" :key="scope" class="scope-item">
|
||
<template v-slot:prepend>
|
||
<v-icon color="success" size="20">mdi-check-circle</v-icon>
|
||
</template>
|
||
<v-list-item-title class="text-body-1">
|
||
{{ getScopeDescription(scope) }}
|
||
</v-list-item-title>
|
||
</v-list-item>
|
||
<v-list-item v-if="scopes.length === 0" class="scope-item">
|
||
<template v-slot:prepend>
|
||
<v-icon color="info" size="20">mdi-information</v-icon>
|
||
</template>
|
||
<v-list-item-title class="text-body-1">
|
||
هیچ مجوز خاصی درخواست نشده است
|
||
</v-list-item-title>
|
||
</v-list-item>
|
||
</v-list>
|
||
</div>
|
||
|
||
<!-- Security Notice -->
|
||
<v-alert type="info" variant="tonal" class="mb-6">
|
||
<template v-slot:prepend>
|
||
<v-icon>mdi-shield-lock</v-icon>
|
||
</template>
|
||
<div>
|
||
<strong>امنیت:</strong> این برنامه فقط به اطلاعات مشخص شده دسترسی خواهد داشت و نمیتواند رمز عبور شما را ببیند.
|
||
</div>
|
||
</v-alert>
|
||
|
||
<!-- Action Buttons -->
|
||
<div class="action-buttons d-flex gap-3">
|
||
<v-btn
|
||
block
|
||
variant="outlined"
|
||
color="error"
|
||
size="large"
|
||
@click="denyAccess"
|
||
:loading="processing"
|
||
>
|
||
<v-icon start>mdi-close</v-icon>
|
||
رد کردن
|
||
</v-btn>
|
||
<v-btn
|
||
block
|
||
color="primary"
|
||
size="large"
|
||
@click="approveAccess"
|
||
:loading="processing"
|
||
>
|
||
<v-icon start>mdi-check</v-icon>
|
||
تایید و ادامه
|
||
</v-btn>
|
||
</div>
|
||
</div>
|
||
</v-card-text>
|
||
</v-card>
|
||
</v-col>
|
||
</v-row>
|
||
</v-container>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import axios from 'axios';
|
||
|
||
export default {
|
||
name: 'OAuthAuthorize',
|
||
data() {
|
||
return {
|
||
loading: true,
|
||
processing: false,
|
||
error: null,
|
||
application: null,
|
||
scopes: [],
|
||
state: null,
|
||
clientId: null,
|
||
redirectUri: null,
|
||
scope: null
|
||
};
|
||
},
|
||
async mounted() {
|
||
await this.initializeAuthorization();
|
||
},
|
||
methods: {
|
||
async initializeAuthorization() {
|
||
try {
|
||
// دریافت پارامترها از URL
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
this.clientId = urlParams.get('client_id');
|
||
this.redirectUri = urlParams.get('redirect_uri');
|
||
this.scope = urlParams.get('scope');
|
||
this.state = urlParams.get('state');
|
||
|
||
// بررسی پارامترهای اجباری
|
||
if (!this.clientId || !this.redirectUri) {
|
||
throw new Error('پارامترهای اجباری موجود نیست');
|
||
}
|
||
|
||
// بررسی وضعیت لاگین کاربر
|
||
const loginCheck = await axios.post('/api/user/check/login');
|
||
if (!loginCheck.data.Success) {
|
||
// اگر کاربر لاگین نیست، به صفحه لاگین هدایت شود
|
||
this.redirectToLogin();
|
||
return;
|
||
}
|
||
|
||
// دریافت اطلاعات برنامه OAuth
|
||
await this.loadApplicationInfo();
|
||
|
||
// پردازش scope ها
|
||
this.scopes = this.scope ? this.scope.split(' ') : [];
|
||
|
||
this.loading = false;
|
||
} catch (error) {
|
||
console.error('Error initializing authorization:', error);
|
||
this.error = error.response?.data?.message || error.message || 'خطا در بارگذاری اطلاعات';
|
||
this.loading = false;
|
||
}
|
||
},
|
||
|
||
async loadApplicationInfo() {
|
||
try {
|
||
const response = await axios.get(`/api/admin/oauth/applications/client/${this.clientId}`);
|
||
if (response.data.Success) {
|
||
this.application = response.data.data;
|
||
} else {
|
||
throw new Error('برنامه یافت نشد');
|
||
}
|
||
} catch (error) {
|
||
throw new Error('خطا در دریافت اطلاعات برنامه');
|
||
}
|
||
},
|
||
|
||
redirectToLogin() {
|
||
const loginUrl = `/user/login?redirect=${encodeURIComponent(window.location.href)}`;
|
||
this.$router.push(loginUrl);
|
||
},
|
||
|
||
async approveAccess() {
|
||
await this.processAuthorization(true);
|
||
},
|
||
|
||
async denyAccess() {
|
||
await this.processAuthorization(false);
|
||
},
|
||
|
||
async processAuthorization(approved) {
|
||
this.processing = true;
|
||
try {
|
||
const response = await axios.post('/api/oauth/authorize', {
|
||
client_id: this.clientId,
|
||
redirect_uri: this.redirectUri,
|
||
scope: this.scope,
|
||
state: this.state,
|
||
approved: approved
|
||
});
|
||
|
||
if (response.data.Success) {
|
||
// هدایت به redirect_uri
|
||
const redirectUrl = response.data.redirect_url;
|
||
window.location.href = redirectUrl;
|
||
} else {
|
||
throw new Error(response.data.message || 'خطا در پردازش مجوز');
|
||
}
|
||
} catch (error) {
|
||
console.error('Authorization error:', error);
|
||
this.error = error.response?.data?.message || error.message || 'خطا در پردازش مجوز';
|
||
this.processing = false;
|
||
}
|
||
},
|
||
|
||
getApplicationIcon() {
|
||
// آیکون پیشفرض برای برنامهها
|
||
return 'mdi-application';
|
||
},
|
||
|
||
getScopeDescription(scope) {
|
||
const scopeDescriptions = {
|
||
'read_profile': 'خواندن اطلاعات پروفایل',
|
||
'write_profile': 'تغییر اطلاعات پروفایل',
|
||
'read_business': 'خواندن اطلاعات کسب و کار',
|
||
'write_business': 'تغییر اطلاعات کسب و کار',
|
||
'read_financial': 'خواندن اطلاعات مالی',
|
||
'write_financial': 'تغییر اطلاعات مالی',
|
||
'read_contacts': 'خواندن لیست مخاطبین',
|
||
'write_contacts': 'تغییر لیست مخاطبین',
|
||
'read_documents': 'خواندن اسناد',
|
||
'write_documents': 'تغییر اسناد',
|
||
'admin_access': 'دسترسی مدیریتی'
|
||
};
|
||
|
||
return scopeDescriptions[scope] || scope;
|
||
},
|
||
|
||
goBack() {
|
||
window.history.back();
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.oauth-authorize-container {
|
||
min-height: 100vh;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
}
|
||
|
||
.oauth-card {
|
||
border-radius: 16px;
|
||
backdrop-filter: blur(10px);
|
||
background: rgba(255, 255, 255, 0.95);
|
||
}
|
||
|
||
.scopes-list {
|
||
background: transparent;
|
||
}
|
||
|
||
.scope-item {
|
||
border-radius: 8px;
|
||
margin-bottom: 8px;
|
||
background: rgba(0, 0, 0, 0.02);
|
||
}
|
||
|
||
.application-info {
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||
padding-bottom: 16px;
|
||
}
|
||
|
||
.action-buttons {
|
||
gap: 12px;
|
||
}
|
||
|
||
/* Responsive Design */
|
||
@media (max-width: 600px) {
|
||
.action-buttons {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.oauth-card {
|
||
margin: 16px;
|
||
}
|
||
}
|
||
</style> |