Skip to content

Commit

Permalink
Merge pull request #60 from nbtca/logto
Browse files Browse the repository at this point in the history
Add login with logto
  • Loading branch information
wen-templari authored Nov 2, 2023
2 parents 3959d10 + b685f87 commit a099958
Show file tree
Hide file tree
Showing 19 changed files with 717 additions and 203 deletions.
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
VITE_LOGTO_CALLBACK_URL=http://localhost:5173/callback
VITE_LOGTO_REDIRECT_URL=http://localhost:5173
VITE_LOGTO_ENDPOINT=https://auth.app.nbtca.space
VITE_LOGTO_APP_ID=h2ejkkfwdtjjpemb021ro
VITE_LOGTO_RESOURCE=https://api.nbtca.space/v2
5 changes: 5 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
VITE_LOGTO_CALLBACK_URL=https://repair.nbtca.space/callback
VITE_LOGTO_REDIRECT_URL=https://repair.nbtca.space:5173
VITE_LOGTO_ENDPOINT=https://auth.app.nbtca.space
VITE_LOGTO_APP_ID=h2ejkkfwdtjjpemb021ro
VITE_LOGTO_RESOURCE=https://api.nbtca.space/v2
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"cellsm",
"innerlg",
"innersm",
"Logto",
"sclass"
],
"testing.automaticallyOpenPeekView": "never"
Expand Down
688 changes: 516 additions & 172 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"dependencies": {
"@headlessui/vue": "^1.4.1",
"@heroicons/vue": "^1.0.4",
"@logto/vue": "^2.0.3",
"axios": "^0.21.4",
"blueimp-md5": "^2.19.0",
"pinia": "^2.0.20",
Expand Down
4 changes: 4 additions & 0 deletions src/assets/images/logto.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions src/components/LogoutButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
import router from "@/router"
import { useAccountStore } from "@/stores/account"
import { useLogto } from "@logto/vue"
const store = useAccountStore()
const { signOut } = useLogto()
const logOut = () => {
const store = useAccountStore()
store.account = {}
store.token = ""
signOut(import.meta.env.VITE_LOGTO_REDIRECT_URL)
}
</script>
<template>
<button @click="logOut">
<slot></slot>
</button>
</template>
21 changes: 7 additions & 14 deletions src/components/Menu/Menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,12 @@
</div>
</div>
</div>
<div class="flex flex-row">
<button class="p-2 rounded" @click="accountSetting">
<div class="flex flex-row items-center gap-4 text-sm">
<button class="rounded-full flex items-center text-blue-600 px-2 py-1" @click="accountSetting">
<CogIcon class="h-6"></CogIcon>
设置
</button>
<button class="p-2 rounded" @click="logOut">
<LogoutIcon class="h-6"></LogoutIcon>
</button>
<logout-button class="p-2 rounded"> 登出 </logout-button>
</div>
</div>
<BottomDialog ref="bottomDialog">
Expand Down Expand Up @@ -128,7 +127,7 @@
</form>
</template>
<template #actionSpace>
<button @click="logOut" class="materialBtn btnWarning mt-1 shadow">登出</button>
<logout-button class="materialBtn btnWarning mt-1 shadow">登出</logout-button>
</template>
</BottomDialog>
</div>
Expand All @@ -142,7 +141,7 @@ import { TransitionRoot } from "@headlessui/vue"
import BottomDialog from "@/components/BottomDialog/BottomDialogBase.vue"
import InputSection from "@/components/Input/InputSection.vue"
import InputBase from "@/components/Input/InputBase.vue"
import logOut from "@/composables/LogOut"
import LogoutButton from "../LogoutButton.vue"
import { useRoute, type RouteRecordRaw } from "vue-router"
import MemberService from "@/services/member"
import CommonService from "@/services/common"
Expand Down Expand Up @@ -184,13 +183,7 @@ const selectedItem = computed(() => {
if (menuList.value == null) {
return null
}
let ans
for (const item of menuList.value) {
if (item.path == pagePath) {
ans = item
}
}
return ans
return menuList.value.find(item => item.path == pagePath)
})
const toLink = (item: RouteRecordRaw) => {
Expand Down
2 changes: 0 additions & 2 deletions src/composables/LogOut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ const logOut = () => {
const store = useAccountStore()
store.account = {}
store.token = ""
localStorage.clear()
router.push("/login")
}

export default logOut
9 changes: 9 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,20 @@ import BottomDialog from "@/components/BottomDialog"
import Notify from "@/components/Notify"
import { BottomDialogInjectionKey } from "./components/BottomDialog/types"
import { NotifyInjectionKey } from "./components/Notify/types"
import { createLogto, type LogtoConfig } from "@logto/vue"

app.provide(BottomDialogInjectionKey, BottomDialog)
app.provide(NotifyInjectionKey, Notify)

app.use(pinia)
app.use(router)

const config: LogtoConfig = {
endpoint: import.meta.env.VITE_LOGTO_ENDPOINT,
appId: import.meta.env.VITE_LOGTO_APP_ID,
resources: [ import.meta.env.VITE_LOGTO_RESOURCE ],
scopes: ["email", "custom_data"],
}

app.use(createLogto, config)
app.mount("#app")
3 changes: 3 additions & 0 deletions src/router/asyncRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const asyncRoutes: RouteRecordRaw[] = [
path: "/",
name: "Index",
component: () => import("@/views/index.vue"),
meta: {
roles: ["admin", "member"],
},
children: [
{
path: "/Events",
Expand Down
5 changes: 5 additions & 0 deletions src/router/constantRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ const constantRoutes: RouteRecordRaw[] = [
name: "Login",
component: () => import("@/views/Login/Login.vue"),
},
{
path: "/callback",
name: "callback",
component: () => import("@/views/CallbackView.vue"),
},
{
path: "/NotFound",
name: "NotFound",
Expand Down
16 changes: 12 additions & 4 deletions src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"
import { createRouter, createWebHistory } from "vue-router"
import constantRoutes from "./constantRoutes"
import asyncRoutes from "./asyncRoutes"
import { useAccountStore } from "@/stores/account"
import { useLogto } from "@logto/vue"

declare module "vue-router" {
interface RouteMeta {
Expand All @@ -19,6 +20,14 @@ const router = createRouter({
})

router.beforeEach((to, from, next) => {
// const { isAuthenticated } = useLogto()

// const target = to.matched[to.matched.length - 1]
// if (!isAuthenticated.value && target.meta.roles && target.meta.roles?.length > 0) {
// next({ path: "/login" })
// return
// }
// next()
const store = useAccountStore()
const token = store.token
let userRole = store.account.role
Expand All @@ -32,7 +41,7 @@ router.beforeEach((to, from, next) => {
return
}
if (!token) {
if (to.path === "/login") {
if (to.path === "/login" || to.path === "/callback") {
next()
} else {
next("/login")
Expand All @@ -45,8 +54,7 @@ router.beforeEach((to, from, next) => {
return
}
// role
const roles = target.meta.role || []
if (!target.meta || !target.meta.roles || roles.length == 0 || roles.indexOf(userRole) !== -1) {
if (!target.meta?.roles || target.meta.roles.length == 0 || target.meta.roles.indexOf(userRole) !== -1) {
if (userRole == "notActivated") {
userRole == "notActivated" ? next({ path: "/notActivated" }) : next()
} else {
Expand Down
46 changes: 46 additions & 0 deletions src/views/CallbackView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script setup lang="ts">
import logOut from "@/composables/LogOut"
import type Member from "@/models/member"
import router from "@/router"
import { useAccountStore } from "@/stores/account"
import Axios from "@/utils/axios"
import { useHandleSignInCallback, useLogto } from "@logto/vue"
import { ref, onMounted } from "vue"
const store = useAccountStore()
const { signIn, signOut, isAuthenticated, fetchUserInfo, getAccessToken } = useLogto()
const authenticateFailed = ref(false)
const { isLoading } = useHandleSignInCallback(async () => {
const token = await getAccessToken(import.meta.env.VITE_LOGTO_RESOURCE)
const res = await window.fetch("/api/member/token/logto", {
headers: {
Authorization: "Bearer " + token,
},
})
const body = await res.json()
if ("token" in body && "memberId" in body && "role" in body) {
store.account = body as Member
store.token = body.token
if (body.role.includes("inactive")) {
router.push("/activate")
router.push("/activate")
} else {
router.push("/Events")
}
} else {
setTimeout(() => {
signOut(import.meta.env.VITE_LOGTO_REDIRECT_URL)
}, 2000)
}
})
</script>

<template>
<div class="p-3">
<p v-if="isLoading">页面跳转中。。。</p>
<p v-if="authenticateFailed">认证失败,跳转至登入页面。</p>
</div>
</template>
4 changes: 2 additions & 2 deletions src/views/Events/EventActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,10 @@ const judgeSubmit = async (event: Event) => {
},
],
acceptAction: () => {
return EventService.close(event.eventId)
return EventService.close(event.eventId as number)
},
declineAction: () => {
return EventService.rejectCommit(event.eventId)
return EventService.rejectCommit(event.eventId as number)
},
})
}
Expand Down
26 changes: 21 additions & 5 deletions src/views/Login/Login.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<template>
<div class="flex flex-col items-center h-screen bg-base-self bg-white">
<div class="flex flex-col items-center sm:mt-16 xl:mt-28">
<div class="py-[5vh] h-80 w-[18vw] sm:h-auto" style="min-width: 250px">
<div class="flex flex-col items-center justify-center h-screen bg-base-self bg-white">
<div class="flex flex-col items-center pb-10">
<div class="w-[18vw] sm:h-auto" style="min-width: 250px">
<img src="../../assets/images/logo.png" alt="" class="filter drop-shadow" />
</div>
<form @submit.prevent="login" class="grid gap-6 place-items-center" style="width: 20vw; min-width: 300px">
<form @submit.prevent="login" class="grid gap-4 place-items-center" style="width: 20vw; min-width: 300px">
<InputBase
placeholder="ID"
hint="学号"
Expand All @@ -24,17 +24,28 @@
/>
<button class="w-full btn bg-gradient-to-b from-primary/80 to-primary text-primaryContent shadow-md" type="submit">登入</button>
</form>
<button
class="w-full btn bg-gradient-to-b from-primary/80 to-primary text-primaryContent shadow-md mt-10"
type="submit"
@click="onSighInWithLogto"
>
<div class="flex items-center gap-2">
<img src="../../assets/images/logto.svg" alt="" class="h-6 w-6" />
<div>使用连接器登入</div>
</div>
</button>
</div>
</div>
</template>
<script setup lang="ts">
import { isFormValid } from "@/utils/isFormValid"
import InputBase from "@/components/Input/InputBase.vue"
import { ref } from "vue"
import { onMounted, ref } from "vue"
import router from "@/router"
import md5 from "blueimp-md5"
import MemberService from "@/services/member"
import { useAccountStore } from "@/stores/account"
import { useLogto } from "@logto/vue"
const store = useAccountStore()
Expand All @@ -45,6 +56,11 @@ const accountInput = ref({
const isIDValid = ref("")
const isPasswordValid = ref("")
const { signIn, isAuthenticated } = useLogto()
const onSighInWithLogto = () => {
signIn(import.meta.env.VITE_LOGTO_CALLBACK_URL)
}
const login = async () => {
isPasswordValid.value = ""
const account = isFormValid(accountInput.value)
Expand Down
6 changes: 4 additions & 2 deletions src/views/Login/LoginActivate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@

<button class="w-full btn bg-primary text-primaryContent mt-5" type="submit">提交</button>
</form>
<button class="w-full btn bg-warning text-primaryContent mt-5" style="width: 17vw; min-width: 300px" @click="logOut">取消</button>
<logout-button class="w-full btn bg-warning text-primaryContent mt-5" style="width: 17vw; min-width: 300px" @click="logOut"
>取消
</logout-button>
</div>
</div>
</template>
Expand All @@ -41,8 +43,8 @@ import { ref, computed } from "vue"
import md5 from "blueimp-md5"
import router from "@/router"
import InputBase from "@/components/Input/InputBase.vue"
import LogoutButton from "@/components/LogoutButton.vue"
import { isFormValid } from "@/utils/isFormValid"
import logOut from "@/composables/LogOut"
import MemberService from "@/services/member"
import { useAccountStore } from "@/stores/account"
Expand Down
Loading

0 comments on commit a099958

Please sign in to comment.