1.add auth token.
This commit is contained in:
parent
3086303ebc
commit
d952110e47
|
@ -1,12 +1,51 @@
|
|||
import { router } from '../router';
|
||||
import { Env } from '../[[path]]'
|
||||
import { json } from 'itty-router-extras';
|
||||
import { Ok, Fail, Build, ImgItem, ImgList, ImgReq, Folder } from "../type";
|
||||
import StatusCode, { Ok, Fail, Build, ImgItem, ImgList, ImgReq, Folder, AuthToken, FailCode, NotAuth } from "../type";
|
||||
import { checkFileType, getFileName, parseRange } from '../utils'
|
||||
import { R2ListOptions } from "@cloudflare/workers-types";
|
||||
|
||||
const auth = async (request : Request, env : Env) => {
|
||||
const method = request.method;
|
||||
// console.log(method)
|
||||
if (method == "GET" || method == "OPTIONS") {
|
||||
return
|
||||
}
|
||||
// get user token
|
||||
const token = request.headers.get('Authorization')
|
||||
if (!token) {
|
||||
return json(NotAuth())
|
||||
}
|
||||
// with kv equal
|
||||
const authKey = await env.XK.get('PICX_AUTH_TOKEN')
|
||||
if (!authKey) {
|
||||
return json(Fail("system not auth setting"))
|
||||
}
|
||||
if (authKey != token) {
|
||||
return json(FailCode("auth fail", StatusCode.NotAuth))
|
||||
}
|
||||
// return new Response('Not Authenticated', { status: 401 })
|
||||
}
|
||||
|
||||
// 检测token是否有效
|
||||
router.post('/checkToken', async (req : Request, env : Env) => {
|
||||
const data = await req.json() as AuthToken
|
||||
const token = data.token
|
||||
if (!token) {
|
||||
return json(Ok(false))
|
||||
}
|
||||
const authKey = await env.XK.get('PICX_AUTH_TOKEN')
|
||||
if (!authKey) {
|
||||
return json(Ok(false))
|
||||
}
|
||||
if (authKey != token) {
|
||||
return json(Ok(false))
|
||||
}
|
||||
return json(Ok(true))
|
||||
})
|
||||
|
||||
// list image
|
||||
router.post('/list', async (req : Request, env : Env) => {
|
||||
router.post('/list', auth, async (req : Request, env : Env) => {
|
||||
const data = await req.json() as ImgReq
|
||||
if (!data.limit) {
|
||||
data.limit = 10
|
||||
|
@ -49,7 +88,7 @@ router.post('/list', async (req : Request, env : Env) => {
|
|||
})
|
||||
|
||||
// batch upload file
|
||||
router.post('/upload', async (req: Request, env : Env) => {
|
||||
router.post('/upload', auth, async (req: Request, env : Env) => {
|
||||
const files = await req.formData()
|
||||
const images = files.getAll("files")
|
||||
const errs = []
|
||||
|
@ -81,22 +120,36 @@ router.post('/upload', async (req: Request, env : Env) => {
|
|||
})
|
||||
|
||||
// 创建目录
|
||||
router.post("/folder", async (req: Request, env: Env) => {
|
||||
router.post("/folder", auth, async (req: Request, env: Env) => {
|
||||
try {
|
||||
const data = await req.json() as Folder
|
||||
const regx = /^[A-Za-z_]+$/
|
||||
if (!regx.test(data.name)) {
|
||||
return json(Fail("Folder name error"))
|
||||
}
|
||||
await env.PICX.put(data.name + '/', "")
|
||||
await env.PICX.put(data.name + '/', null)
|
||||
return json(Ok("Success"))
|
||||
} catch (e) {
|
||||
return json(Fail("Create folder fail"))
|
||||
}
|
||||
})
|
||||
|
||||
// 删除key
|
||||
router.get('/del/:id+', async (req : Request, env: Env) => {
|
||||
const key = req.params.id
|
||||
if (!key) {
|
||||
return json(Fail("not delete key"))
|
||||
}
|
||||
try {
|
||||
await env.PICX.delete(key)
|
||||
} catch (e) {
|
||||
console.log(`img delete error:${e.message}`,)
|
||||
}
|
||||
return json(Ok(key))
|
||||
})
|
||||
|
||||
// delete image
|
||||
router.delete("/", async (req : Request, env: Env) => {
|
||||
router.delete("/", auth, async (req : Request, env: Env) => {
|
||||
const params = await req.json()
|
||||
// console.log(params)
|
||||
const keys = params.keys;
|
||||
|
|
|
@ -29,6 +29,22 @@ export interface Folder {
|
|||
name: string
|
||||
}
|
||||
|
||||
export function NotAuth() : Result {
|
||||
return <Result> {
|
||||
code: StatusCode.NotAuth,
|
||||
msg: "Not Authorization",
|
||||
data: null
|
||||
}
|
||||
}
|
||||
|
||||
export function FailCode(msg : string, code: number) : Result {
|
||||
return <Result> {
|
||||
code: code,
|
||||
msg: msg,
|
||||
data: null
|
||||
}
|
||||
}
|
||||
|
||||
export function Fail(msg : string) : Result {
|
||||
return <Result> {
|
||||
code: StatusCode.ERROR,
|
||||
|
@ -52,6 +68,11 @@ export function Build(data : any, msg: string) : Result {
|
|||
}
|
||||
const StatusCode = {
|
||||
OK: 200,
|
||||
ERROR: 500
|
||||
ERROR: 500,
|
||||
NotAuth: 401
|
||||
}
|
||||
|
||||
export interface AuthToken {
|
||||
token: string
|
||||
}
|
||||
export default StatusCode
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import './permission'
|
||||
import router from './plugins/router'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
import './app.css'
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import router from "./plugins/router"
|
||||
import storage from "./utils/storage";
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
// console.log(to.path)
|
||||
const path = to.path
|
||||
const token = storage.local.get('auth-token')
|
||||
if (path != '/auth' && !token) {
|
||||
router.push('/auth')
|
||||
return
|
||||
}
|
||||
next()
|
||||
})
|
|
@ -11,6 +11,10 @@ const router = createRouter({
|
|||
path: '/up',
|
||||
component: () => import('../views/UploadImages.vue')
|
||||
},
|
||||
{
|
||||
path: '/auth',
|
||||
component: () => import('../views/auth.vue')
|
||||
},
|
||||
{
|
||||
path: '/:path(.*)',
|
||||
redirect: '/'
|
||||
|
|
|
@ -1,14 +1,44 @@
|
|||
import axios from 'axios'
|
||||
import { ElNotification as elNotify } from 'element-plus'
|
||||
import {ImgList, ImgDel, ImgReq, Folder, ImgItem} from "./types";
|
||||
|
||||
import {ImgList, ImgDel, ImgReq, Folder, ImgItem, AuthToken} from "./types"
|
||||
import storage from "./storage"
|
||||
const request = axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_API_URL,
|
||||
timeout: 200000
|
||||
})
|
||||
|
||||
request.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = storage.local.get('auth-token')
|
||||
if (token) {
|
||||
// @ts-ignore
|
||||
config.headers['Authorization'] = token
|
||||
}
|
||||
return config
|
||||
}
|
||||
)
|
||||
|
||||
request.interceptors.response.use(
|
||||
(response) => response.data.data,
|
||||
(response) => {
|
||||
const data = response.data;
|
||||
// console.log(data)
|
||||
if (data.code === 401) {
|
||||
// 跳转到登陆页面
|
||||
// 移除token
|
||||
storage.local.remove('auth-token')
|
||||
window.location.href = '/auth'
|
||||
return Promise.reject(data.msg)
|
||||
}
|
||||
if (data.code !== 200) {
|
||||
elNotify({
|
||||
message: data.msg,
|
||||
duration: 0,
|
||||
type: 'error'
|
||||
})
|
||||
return Promise.reject(data.msg)
|
||||
}
|
||||
return data.data
|
||||
},
|
||||
(error) => {
|
||||
elNotify({
|
||||
message: error?.response?.data || String(error),
|
||||
|
@ -22,4 +52,5 @@ request.interceptors.response.use(
|
|||
export const requestListImages = (data : ImgReq): Promise<ImgList> => request.post('/rest/list', data)
|
||||
export const requestUploadImages = (data: FormData) : Promise<ImgItem[]> => request.post('/rest/upload', data)
|
||||
export const createFolder = (data: Folder) => request.post('/rest/folder', data)
|
||||
export const checkToken = (data: AuthToken) => request.post('/rest/checkToken', data)
|
||||
export const requestDeleteImage = (data: ImgDel) => request.delete('/rest', { data })
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
const globalObj = {}
|
||||
const KEY_PEX = 'ROIM-'
|
||||
class WebStorage {
|
||||
storage: Storage;
|
||||
constructor(storage: Storage) {
|
||||
this.storage = storage
|
||||
}
|
||||
get(key : string) {
|
||||
const valueStr = this.storage.getItem(KEY_PEX + key)
|
||||
if (!valueStr) {
|
||||
return ''
|
||||
}
|
||||
if (!valueStr) {
|
||||
return ''
|
||||
}
|
||||
try {
|
||||
return JSON.parse(valueStr)
|
||||
} catch (e) {
|
||||
return valueStr
|
||||
}
|
||||
}
|
||||
set(key : string, value : any) {
|
||||
const valueStr = JSON.stringify(value)
|
||||
return this.storage.setItem(KEY_PEX + key, valueStr)
|
||||
}
|
||||
remove(key : string) {
|
||||
this.storage.removeItem(KEY_PEX + key)
|
||||
}
|
||||
removeAll() {
|
||||
this.storage.clear()
|
||||
}
|
||||
}
|
||||
const storage = {
|
||||
local: new WebStorage(window.localStorage),
|
||||
session: new WebStorage(window.sessionStorage)
|
||||
}
|
||||
export default storage
|
|
@ -11,6 +11,9 @@ export type UploadedImage = {
|
|||
expiresAt: number
|
||||
}
|
||||
|
||||
export interface AuthToken {
|
||||
token: string
|
||||
}
|
||||
export interface ImgItem {
|
||||
key : string
|
||||
url : string
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<span v-else class="pl-2 text-gray-600"> {{ it }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-4 lg:grid-cols-4 grid-cols-2">
|
||||
<div class="grid gap-2 lg:gap-4 lg:grid-cols-4 grid-cols-2">
|
||||
<transition-group name="el-fade-in-linear">
|
||||
<div
|
||||
class="col-span-1 md:col-span-1"
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div class="mx-auto max-w-6xl my-4 px-4 relative">
|
||||
<div class="mx-auto max-w-2xl mt-10">
|
||||
<el-input v-model="token" size="large" class="h-12" placeholder="请输入认证Token" />
|
||||
<el-button :loading="loading" class="mt-4 w-full lg:w-6xl" size="large" type="primary" @click="saveToken">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElInput, ElButton, ElMessage } from 'element-plus'
|
||||
import storage from '../utils/storage'
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { checkToken } from '../utils/request'
|
||||
const token = ref('')
|
||||
const loading = ref(false)
|
||||
const router = useRouter()
|
||||
const saveToken = () => {
|
||||
loading.value = true
|
||||
if (!token.value) {
|
||||
loading.value = false
|
||||
ElMessage.error('请输入token')
|
||||
return
|
||||
}
|
||||
checkToken({
|
||||
token: token.value
|
||||
}).then(res => {
|
||||
if (res) {
|
||||
// 检测token是否有效
|
||||
storage.local.set('auth-token', token.value)
|
||||
router.push('/')
|
||||
} else {
|
||||
ElMessage.error('Token无效')
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue