Skip to content

Commit

Permalink
优化登录
Browse files Browse the repository at this point in the history
  • Loading branch information
jooooock committed Sep 23, 2024
1 parent 5dd6b20 commit b29b117
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 76 deletions.
4 changes: 2 additions & 2 deletions components/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
</a>
</div>
<div v-if="loginAccount" class="flex flex-col sm:flex-row items-center sm:space-x-2 ml-5">
<img v-if="loginAccount.head_img" :src="loginAccount.head_img" alt="" class="rounded-full size-10">
<span v-if="loginAccount.nick_name">{{loginAccount.nick_name}}</span>
<img v-if="loginAccount.avatar" :src="loginAccount.avatar" alt="" class="rounded-full size-10">
<span v-if="loginAccount.nickname">{{loginAccount.nickname}}</span>
</div>
</header>

Expand Down
10 changes: 5 additions & 5 deletions pages/dashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
<!-- footer -->
<footer v-if="loginAccount" class="flex flex-col space-y-2 pt-3 border-t">
<div class="flex items-center space-x-2">
<img v-if="loginAccount.head_img" :src="loginAccount.head_img" alt="" class="rounded-full size-10">
<UTooltip v-if="loginAccount.nick_name" class="flex-1 overflow-hidden"
<img v-if="loginAccount.avatar" :src="loginAccount.avatar" alt="" class="rounded-full size-10">
<UTooltip v-if="loginAccount.nickname" class="flex-1 overflow-hidden"
:popper="{ placement: 'top-start', offsetDistance: 16 }">
<template #text>
<span>{{ loginAccount.nick_name }}</span>
<span>{{ loginAccount.nickname }}</span>
</template>
<span class="whitespace-nowrap text-ellipsis overflow-hidden">{{ loginAccount.nick_name }}</span>
<span class="whitespace-nowrap text-ellipsis overflow-hidden">{{ loginAccount.nickname }}</span>
</UTooltip>

<UButton icon="i-heroicons-arrow-left-start-on-rectangle-16-solid" :loading="logoutBtnLoading"
Expand Down Expand Up @@ -110,7 +110,7 @@ const items = ref([
{name: '设置', icon: Settings, href: '/dashboard/settings'},
])
const expire = localStorage.getItem('token-expire')!
const expire = loginAccount.value.expires
const now = ref(new Date())
const distance = computed(() => {
return formatDistance(new Date(expire), now.value, {
Expand Down
16 changes: 0 additions & 16 deletions pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

<script setup lang="ts">
import type ArticleList from "~/components/ArticleList.vue";
import type {LoginInfoResult} from "~/types/types";
definePageMeta({
Expand All @@ -25,7 +24,6 @@ useHead({
title: '微信公众号文章导出'
})
const loginAccount = useLoginAccount()
const activeAccount = useActiveAccount()
const articleListRef = ref<typeof ArticleList | null>(null)
Expand All @@ -40,18 +38,4 @@ function selectAccount() {
function searchArticle(query: string) {
articleListRef.value?.init(query)
}
onMounted(async () => {
// 获取更多账号信息
if (!loginAccount.value.nick_name) {
try {
const {nick_name, head_img} = await $fetch<LoginInfoResult>(`/api/login/info?token=${loginAccount.value.token}`)
loginAccount.value.nick_name = nick_name
loginAccount.value.head_img = head_img
} catch (e) {
console.info('获取账号信息失败')
console.error(e)
}
}
})
</script>
28 changes: 16 additions & 12 deletions pages/login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
</template>

<script setup lang="ts">
import type {BizLoginResult, ScanLoginResult, StartLoginResult} from "~/types/types";
import type {LoginAccount, ScanLoginResult, StartLoginResult} from "~/types/types";
const qrcodeSrc = ref('')
Expand All @@ -117,6 +117,7 @@ const sessionid = new Date().getTime().toString() + Math.floor(Math.random() * 1
const hasStartLogin = ref(false)
const loginAccount = useLoginAccount()
const activeAccount = useActiveAccount()
useHead({
Expand Down Expand Up @@ -233,21 +234,24 @@ async function checkQrcode() {
}
async function bizLogin() {
const result = await $fetch<BizLoginResult>('/api/login/bizlogin', {
const result = await $fetch<LoginAccount>('/api/login/bizlogin', {
method: 'POST'
})
const cookie = document.cookie.split(';').map(v => v.trim()).find(cookie => cookie.startsWith('token-expire='))
if (cookie) {
const expire = cookie.split('=')[1]
localStorage.setItem('token-expire', expire)
}
// /cgi-bin/home?t=home/index&lang=zh_CN&token=1416430543
const _token = new URL(`http://localhost${result.redirect_url}`).searchParams.get('token')
if (_token) {
if (result.token) {
console.log('登录成功')
loginAccount.value = {
token: _token,
loginAccount.value = result
if (!activeAccount.value) {
activeAccount.value = {
type: 'account',
fakeid: result.fakeid,
nickname: result.nickname,
round_head_img: result.avatar,
service_type: 1,
alias: '',
signature: '',
}
}
navigateTo('/', {replace: true})
Expand Down
92 changes: 83 additions & 9 deletions server/api/login/bizlogin.post.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {proxyMpRequest} from "~/server/utils";
import {createUser, type User} from "~/server/utils/kv";


export default defineEventHandler(async (event) => {
const body: Record<string, string | number> = {
Expand All @@ -24,18 +26,90 @@ export default defineEventHandler(async (event) => {
body: body,
})

const headers = new Headers(response.headers)

const cookies = response.headers.getSetCookie()
const cookie = cookies.find(cookie => cookie.includes('slave_sid='))
if (cookie) {
const parts = cookie.split(';').map(v => v.trim())
const expirePart = parts.find(part => part.startsWith('Expires='))
if (expirePart) {
const expire = expirePart.split('=')[1]
headers.append('Set-Cookie', `token-expire=${expire};path=/`)
const parsedCookies = parseCookies(cookies)

const _body = await response.json()
const _token = new URL(`http://localhost${_body.redirect_url}`).searchParams.get('token')
const _cookie: string[] = []
Object.keys(parsedCookies).forEach(key => {
_cookie.push(key + '=' + parsedCookies[key].value)
})
const {nick_name, head_img} = await $fetch(`/api/login/info?token=${_token}`, {
headers: {
Cookie: _cookie.join(';')
}
})
const searchResult = await $fetch(`/api/searchbiz?token=${_token}&keyword=${nick_name}`, {
headers: {
Cookie: _cookie.join(';')
}
})
let _fakeid = ''
let _avatar = head_img
if (searchResult && searchResult.base_resp && searchResult.base_resp.ret === 0) {
const account = searchResult.list.find((account: any) => account.nickname === nick_name)
if (account) {
_fakeid = account.fakeid
_avatar = account.round_head_img
}
}

// 创建用户
const user: User = {
uuid: crypto.randomUUID(),
fakeid: _fakeid,
originalID: parsedCookies['slave_user'].value,
nickname: nick_name,
avatar: _avatar,
createdAt: new Date().getTime(),
}
if (await createUser(user)) {
console.log(`新用户(${user.nickname}:${user.uuid})创建成功`)
}


const newBody = JSON.stringify({
uuid: user.uuid,
nickname: user.nickname,
avatar: user.avatar,
fakeid: user.fakeid,
token: _token,
expires: parsedCookies['slave_sid'].expires,
})

return new Response(response.body, {headers: headers})
const headers = new Headers(response.headers)
headers.set('Content-Length', new TextEncoder().encode(newBody).length.toString())
return new Response(newBody, {headers: headers})
})

interface CookieItem {
name: string
value: string
path: string
expires: string
secure: boolean
httpOnly: boolean
}

function parseCookies (cookies: string[]): Record<string, CookieItem> {
const result: Record<string, CookieItem> = {}
cookies.forEach(cookie => {
const parts = cookie.split(';').map(v => v.trim())
const [name, value] = parts[0].split('=')
const other = parts.slice(1).map(v => v.toLowerCase())

const pathPart = other.find(part => part.startsWith('path='))
const expirePart = other.find(part => part.startsWith('expires='))
result[name] = {
name: name,
value: value,
path: pathPart?.split('=')[1] || '/',
expires: expirePart?.split('=')[1] || '',
secure: other.includes('secure'),
httpOnly: other.includes('httponly'),
}
})
return result
}
55 changes: 30 additions & 25 deletions server/api/stat.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,62 @@ import {formatTraffic} from "~/server/utils";
*/
interface ProxyInstance {
// 代理地址
address: string
address: string;

// 是否正在被使用
busy: boolean
busy: boolean;

// 是否处于冷静期
cooldown: boolean
cooldown: boolean;

// 使用次数
usageCount: number
usageCount: number;

// 成功次数
successCount: number
successCount: number;

// 失败次数
failureCount: number
failureCount: number;

// 下载流量
traffic: number
traffic: number;
}

interface ProxyUsageReport {
fakeId: string
nickname: string
account: string
proxies: ProxyInstance[]
fakeId: string;
nickname: string;
account: string;
proxies: ProxyInstance[];
}

export default defineEventHandler(async (event) => {
const body = await readBody<ProxyUsageReport>(event)
const body = await readBody<ProxyUsageReport>(event);

let totalCount = 0
let totalTraffic = 0
let totalCount = 0;
let totalTraffic = 0;
for (const proxy of body.proxies) {
totalCount += proxy.usageCount
totalTraffic += proxy.traffic
totalCount += proxy.usageCount;
totalTraffic += proxy.traffic;
}

console.log(
`%c${body.account}%c use %c${totalCount}%c proxy, total traffic is %c${formatTraffic(totalTraffic)}%c`,
`%c${body.account}%c use %c${totalCount}%c proxy, total traffic is %c${
formatTraffic(totalTraffic)
}%c`,
"color: green; font-weight: bold;",
"color: black; font-weight: normal;",
"color: red; font-weight: bold;",
"color: black; font-weight: normal;",
"color: red; font-weight: bold;",
"color: black; font-weight: normal;",
)

const kv = await useKv()
const op = kv.atomic()
op.set(['proxy', body.account, body.nickname, Date.now()], body)
await op.commit()
kv.close()
})
);

const kv = await useKv();
const res = await kv.atomic()
.set(["proxy", body.account, body.nickname, Date.now()], body)
.commit();
if (!res.ok) {
console.warn('统计数据写入失败')
}
kv.close();
});
24 changes: 24 additions & 0 deletions server/utils/kv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,27 @@ export const useKv = async () => {
message: 'Could not find a Deno KV for production, make sure to deploy on Deno Deploy.'
})
}

export interface User {
uuid: string
fakeid: string
originalID: string
nickname: string
avatar: string
createdAt: number
}

/**
* 创建新用户
* @param user
*/
export async function createUser(user: User): Promise<boolean> {
const key = ["users", user.originalID]

const kv = await useKv()
const res = await kv.atomic()
.check({key, versionstamp: null})
.set(key, user)
.commit()
return !!res.ok
}
12 changes: 5 additions & 7 deletions types/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export interface LoginAccount {
uuid: string
token: string
nick_name?: string
head_img?: string
nickname: string
avatar: string
fakeid: string
expires: string
}

export interface LoginInfoResult {
Expand All @@ -25,11 +28,6 @@ export interface ScanLoginResult {
binduin: string
}

export interface BizLoginResult {
base_resp: BaseResp
redirect_url: string
}

export interface AccountInfo {
type: 'account'
alias: string
Expand Down

0 comments on commit b29b117

Please sign in to comment.