updated
This commit is contained in:
parent
50eecafad2
commit
b8e1c415e1
18 changed files with 601 additions and 110 deletions
|
|
@ -1,16 +1,173 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted } from "vue";
|
||||
import { deleteCookie, getCookie, setCookie } from "@/plugins/cookie";
|
||||
import router from "@/router";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { useQuasar } from "quasar";
|
||||
import axios from "axios";
|
||||
|
||||
import CustomComponent from "@/components/CustomDialog.vue";
|
||||
|
||||
const $q = useQuasar();
|
||||
|
||||
const urlAdmin = import.meta.env.VITE_URL_ADMIN ?? "";
|
||||
const urlUser = import.meta.env.VITE_URL_USER ?? "";
|
||||
const urlMgt = import.meta.env.VITE_URL_MGT ?? "";
|
||||
const urlCheckin = import.meta.env.VITE_URL_CHECKIN ?? "";
|
||||
|
||||
const token = ref<any>("");
|
||||
const refreshToken = ref<any>("");
|
||||
const fullname = computed(() => {
|
||||
if (token.value) {
|
||||
const base64Url = token.value.split(".")[1];
|
||||
|
||||
// แปลงจาก Base64 URL-safe เป็น Base64 ปกติ
|
||||
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
||||
|
||||
// ถอดรหัส Base64
|
||||
const decoded = atob(base64);
|
||||
const decodedData = JSON.parse(decoded);
|
||||
|
||||
// ดึงชื่อผู้ใช้
|
||||
return decodeURIComponent(escape(decodedData.name));
|
||||
} else return "";
|
||||
});
|
||||
|
||||
async function goPage(sys: string, url: string) {
|
||||
// แยกส่วน Payload ของ JWT (ส่วนที่ 2)
|
||||
const base64Url = token.value.split(".")[1];
|
||||
|
||||
// แปลงจาก Base64 URL-safe เป็น Base64 ปกติ
|
||||
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
||||
|
||||
// ถอดรหัส Base64
|
||||
const decoded = atob(base64);
|
||||
|
||||
// กำหนด requiredRole ตามค่าของ sys
|
||||
let requiredRole: string[] = [];
|
||||
|
||||
if (sys === "user" || sys === "checkin") {
|
||||
requiredRole = ["USER"];
|
||||
} else if (sys === "mgt") {
|
||||
requiredRole = ["STAFF"]; // ถ้า sys เป็นค่าว่าง ให้ใช้ "ADMIN"
|
||||
} else if (sys === "admin") {
|
||||
requiredRole = ["ADMIN", "SUPER_ADMIN"];
|
||||
}
|
||||
|
||||
console.log("requiredRole===>", requiredRole);
|
||||
console.log("decoded===>", JSON.parse(decoded).realm_access.roles);
|
||||
|
||||
// ตรวจสอบว่า payload.role มีค่าหรือไม่ และว่ามี role ที่ต้องการหรือไม่
|
||||
if (
|
||||
requiredRole.some((role) =>
|
||||
JSON.parse(decoded).realm_access.roles.includes(role)
|
||||
)
|
||||
) {
|
||||
window.location.href = `${url}/auth?token=${token.value}&accessToken=${refreshToken.value}`;
|
||||
} else {
|
||||
// alert("คุณไม่มีสิทธิ์เข้าใช้งานระบบนี้");
|
||||
$q.dialog({
|
||||
component: CustomComponent,
|
||||
componentProps: {
|
||||
title: `แจ้งเตือน`,
|
||||
message: "คุณไม่มีสิทธิ์เข้าใช้งานระบบนี้",
|
||||
icon: "warning",
|
||||
color: "red",
|
||||
onlycancel: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
await deleteCookie("BMAHRIS_KEYCLOAK_IDENTITY");
|
||||
await deleteCookie("BMAHRIS_KEYCLOAK_REFRESH");
|
||||
|
||||
router.push("/sso");
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// const checkAuthen = await authenticated();
|
||||
// if (checkAuthen) {
|
||||
// router.push("/");
|
||||
// }
|
||||
token.value = await getCookie("BMAHRIS_KEYCLOAK_IDENTITY");
|
||||
refreshToken.value = await getCookie("BMAHRIS_KEYCLOAK_REFRESH");
|
||||
|
||||
deleteCookie("BMAHRISADM_KEYCLOAK_IDENTITY");
|
||||
deleteCookie("BMAHRISCKI_KEYCLOAK_IDENTITY");
|
||||
deleteCookie("BMAHRISUSER_KEYCLOAK_IDENTITY");
|
||||
|
||||
const checkToken = (await token.value) ?? null;
|
||||
|
||||
if (!checkToken && !token.value) {
|
||||
await axios
|
||||
.post(
|
||||
`${import.meta.env.VITE_SSO_URL}/kcauth`,
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
withCredentials: true, // Include cookies with the request
|
||||
}
|
||||
)
|
||||
.then((res: any) => {
|
||||
console.log("res===>", res);
|
||||
|
||||
if (res.status === 200) {
|
||||
setCookie("BMAHRIS_KEYCLOAK_IDENTITY", res.data.access_token, 1);
|
||||
setCookie("BMAHRIS_KEYCLOAK_REFRESH", res.data.refresh_token, 1);
|
||||
}
|
||||
})
|
||||
.catch((err: any) => {
|
||||
router.push("/sso");
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>Lanading page</h1>
|
||||
<div class="q-ma-md">
|
||||
<div class="row">
|
||||
{{ fullname }}
|
||||
<q-btn @click="logout()" class="btn_logout">
|
||||
ออกจากระบบ <i class="mdi mdi-logout"></i>
|
||||
</q-btn>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<img src="@/assets/screen1.png" style="width: 100%" />
|
||||
<div class="h-100 py-3">
|
||||
<a @click="goPage('user', urlUser)" class="link">
|
||||
ระบบบริการเจ้าของข้อมูล
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<img src="@/assets/screen2.png" style="width: 100%" />
|
||||
<div class="h-100 py-3">
|
||||
<a @click="goPage('checkin', urlCheckin)" class="link">
|
||||
ระบบลงเวลาปฏิบัติราชการ
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<img src="@/assets/screen3.png" style="width: 100%" />
|
||||
<div class="h-100 py-3">
|
||||
<a @click="goPage('mgt', urlMgt)" class="link"> ระบบบริหารจัดการ </a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<img src="@/assets/screen4.png" style="width: 100%" />
|
||||
<div class="h-100 py-3">
|
||||
<a @click="goPage('admin', urlAdmin)" class="link"> ระบบแอดมิน </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.link {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
298
src/views/sso.vue
Normal file
298
src/views/sso.vue
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
<!-- authen with keycloak client -->
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { useQuasar } from "quasar";
|
||||
import axios from "axios";
|
||||
|
||||
import { useRouter } from "vue-router";
|
||||
import { useCounterMixin } from "@/stores/mixin";
|
||||
|
||||
const $q = useQuasar();
|
||||
const router = useRouter();
|
||||
const mixin = useCounterMixin();
|
||||
|
||||
const { showLoader, hideLoader } = mixin;
|
||||
|
||||
const username = ref<string>(""); // ผู้ใช้
|
||||
const password = ref<string>(""); // รหัสผ่าน
|
||||
const msgError = ref<string>(""); // ข้อความแสดงข้อผิดพลาด
|
||||
/**
|
||||
* ฟังก์ชั่นเข้าสู่ระบบ
|
||||
*/
|
||||
async function onSubmit() {
|
||||
showLoader();
|
||||
msgError.value = "";
|
||||
// const formdata = new URLSearchParams();
|
||||
// formdata.append("username", username.value);
|
||||
// formdata.append("password", password.value);
|
||||
|
||||
await axios
|
||||
.post(
|
||||
`${import.meta.env.VITE_SSO_URL}/signin`,
|
||||
{
|
||||
username: username.value,
|
||||
password: password.value,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
withCredentials: true, // Include cookies with the request
|
||||
}
|
||||
)
|
||||
.then((res) => {
|
||||
if (res.data === "OK") {
|
||||
router.push("/");
|
||||
}
|
||||
console.log("res===>", res);
|
||||
})
|
||||
.catch((err) => {
|
||||
msgError.value = "ชื่อผู้ใช้งานหรือรหัสผ่านไม่ถูกต้อง";
|
||||
})
|
||||
.finally(() => {
|
||||
hideLoader();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ทำงานเมื่อ components ถูกเรียกใช้งาน
|
||||
*/
|
||||
onMounted(async () => {});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-image">
|
||||
<div class="shadow-top"></div>
|
||||
<div class="shadow-bottom"></div>
|
||||
<div class="row fit items-center">
|
||||
<div class="row full-width justify-evenly">
|
||||
<div class="">
|
||||
<div id="myimage"></div>
|
||||
|
||||
<div class="text-logo">
|
||||
ระบบบริหารจัดการการใช้งาน <br />ระบบสารสนเทศสนับสนุนการเชื่อมโยง
|
||||
</div>
|
||||
<div class="subtext-logo">
|
||||
Bangkok Metropolitan Administration Single Sign-On
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img src="@/assets/line.png" class="img_absolute_line" />
|
||||
|
||||
<div class="card-pf">
|
||||
<div class="row q-gutter-sm items-center q-mb-sm">
|
||||
<div class="column">
|
||||
<div class="login-pf-header">
|
||||
<h1 id="kc-page-title">เข้าใช้งานระบบ</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<q-form
|
||||
greedy
|
||||
@submit.prevent
|
||||
@validation-success="onSubmit"
|
||||
style="max-width: 100%; min-width: 30%"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-12 form-group">
|
||||
<label
|
||||
for="username"
|
||||
class="pf-c-form__label pf-c-form__label-text"
|
||||
>ชื่อผู้ใช้งาน</label
|
||||
>
|
||||
<q-input
|
||||
v-model="username"
|
||||
dense
|
||||
outlined
|
||||
lazy-rules
|
||||
hide-bottom-space
|
||||
:rules="[(val:string) => !!val || `${'กรุณากรอกชื่อผู้ใช้งาน'}`,]"
|
||||
></q-input>
|
||||
</div>
|
||||
<div class="col-12 form-group">
|
||||
<label
|
||||
for="username"
|
||||
class="pf-c-form__label pf-c-form__label-text"
|
||||
>รหัสผ่าน</label
|
||||
>
|
||||
<q-input
|
||||
v-model="password"
|
||||
dense
|
||||
outlined
|
||||
lazy-rules
|
||||
hide-bottom-space
|
||||
type="password"
|
||||
:rules="[(val:string) => !!val || `${'กรุณากรอกรหัสผ่าน'}`,]"
|
||||
></q-input>
|
||||
</div>
|
||||
|
||||
<div class="col-12 text-red text-center">{{ msgError }}</div>
|
||||
<div class="col-12">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="primary"
|
||||
class="full-width"
|
||||
label="เข้าระบบ"
|
||||
style="font-size: 16px; border-radius: 8px"
|
||||
type="submit"
|
||||
>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</q-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.shadow-top {
|
||||
position: absolute;
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
border-radius: 50%;
|
||||
background-color: $primary;
|
||||
top: -4rem;
|
||||
right: -4rem;
|
||||
opacity: 0.5;
|
||||
box-shadow: 0px 0px 300px 320px $primary;
|
||||
backdrop-filter: blur(550px);
|
||||
}
|
||||
.shadow-bottom {
|
||||
position: absolute;
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
border-radius: 50%;
|
||||
background-color: $primary;
|
||||
bottom: -4rem;
|
||||
left: -4rem;
|
||||
opacity: 0.5;
|
||||
box-shadow: 0px 0px 300px 320px $primary;
|
||||
backdrop-filter: blur(550px);
|
||||
}
|
||||
|
||||
.color-icon {
|
||||
border-radius: 8px;
|
||||
}
|
||||
.link {
|
||||
text-decoration: none;
|
||||
color: #cc0004;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
color: #ff0004;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.checkbox,
|
||||
.radio {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
margin: 1px 3px 0 0;
|
||||
line-height: normal;
|
||||
}
|
||||
.checkbox label,
|
||||
.radio label {
|
||||
min-height: 20px;
|
||||
margin-bottom: 0;
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
text-align: left;
|
||||
}
|
||||
#kc-content {
|
||||
width: 100%;
|
||||
}
|
||||
#kc-content-wrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
#kc-form-options .checkbox {
|
||||
margin-top: 0;
|
||||
color: #72767b;
|
||||
}
|
||||
.bg-image {
|
||||
font-family: "Noto Sans Thai", sans-serif;
|
||||
font-family: "Noto Sans Thai", sans-serif;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background-size: cover;
|
||||
height: 100vh;
|
||||
background: rgb(30, 50, 49);
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
rgba(30, 50, 49, 1) 0%,
|
||||
rgba(20, 120, 99, 1) 100%
|
||||
);
|
||||
}
|
||||
|
||||
#myimage {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
object-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% !important;
|
||||
background: url(@/assets/logo.png) no-repeat center center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.text-logo {
|
||||
text-align: left;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.subtext-logo {
|
||||
color: #fff;
|
||||
font-weight: 200;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.card-pf {
|
||||
padding: 20px;
|
||||
max-width: 400px;
|
||||
min-width: 30%;
|
||||
position: relative;
|
||||
z-index: 10 !important;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-header {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-header h1 {
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
h1#kc-page-title {
|
||||
font-weight: 800;
|
||||
font-size: 1.3rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-header h1 {
|
||||
font-size: 16px;
|
||||
}
|
||||
.img_absolute_line {
|
||||
position: absolute;
|
||||
height: auto;
|
||||
width: 400px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue