1.add auth token.

This commit is contained in:
atom 2023-03-24 15:23:15 +08:00
parent 3086303ebc
commit d952110e47
10 changed files with 219 additions and 11 deletions

View File

@ -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;

View File

@ -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

View File

@ -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'

13
src/permission.ts Normal file
View File

@ -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()
})

View File

@ -11,6 +11,10 @@ const router = createRouter({
path: '/up',
component: () => import('../views/UploadImages.vue')
},
{
path: '/auth',
component: () => import('../views/auth.vue')
},
{
path: '/:path(.*)',
redirect: '/'

View File

@ -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 })

37
src/utils/storage.ts Normal file
View File

@ -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

View File

@ -11,6 +11,9 @@ export type UploadedImage = {
expiresAt: number
}
export interface AuthToken {
token: string
}
export interface ImgItem {
key : string
url : string

View File

@ -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"

45
src/views/auth.vue Normal file
View File

@ -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>