Add JWT auth with per-user data isolation and account settings.
Users can register, log in, and manage profile/password in a personal account page; server data is scoped by owner across contacts, maps, tags, and import. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import api from '../api'
|
||||
|
||||
const TOKEN_KEY = 'sg-access-token'
|
||||
const REFRESH_KEY = 'sg-refresh-token'
|
||||
const USER_KEY = 'sg-user'
|
||||
|
||||
function readUser() {
|
||||
try {
|
||||
const raw = localStorage.getItem(USER_KEY)
|
||||
return raw ? JSON.parse(raw) : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function persistSession({ access, refresh, user }) {
|
||||
if (access) localStorage.setItem(TOKEN_KEY, access)
|
||||
if (refresh) localStorage.setItem(REFRESH_KEY, refresh)
|
||||
if (user) localStorage.setItem(USER_KEY, JSON.stringify(user))
|
||||
}
|
||||
|
||||
function clearSessionStorage() {
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
localStorage.removeItem(REFRESH_KEY)
|
||||
localStorage.removeItem(USER_KEY)
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: () => ({
|
||||
accessToken: localStorage.getItem(TOKEN_KEY) || '',
|
||||
refreshToken: localStorage.getItem(REFRESH_KEY) || '',
|
||||
user: readUser(),
|
||||
}),
|
||||
|
||||
getters: {
|
||||
isAuthenticated: (state) => Boolean(state.accessToken),
|
||||
username: (state) => state.user?.username || '',
|
||||
userId: (state) => state.user?.id ?? null,
|
||||
},
|
||||
|
||||
actions: {
|
||||
setSession({ access, refresh, user }) {
|
||||
this.accessToken = access || ''
|
||||
this.refreshToken = refresh || ''
|
||||
this.user = user || null
|
||||
persistSession({ access, refresh, user })
|
||||
},
|
||||
|
||||
async register({ username, email, password }) {
|
||||
const { data } = await api.post('/v1/auth/register/', {
|
||||
username: username.trim(),
|
||||
email: (email || '').trim(),
|
||||
password,
|
||||
})
|
||||
this.setSession(data)
|
||||
return data
|
||||
},
|
||||
|
||||
async login({ username, password }) {
|
||||
const { data } = await api.post('/v1/auth/token/', {
|
||||
username: username.trim(),
|
||||
password,
|
||||
})
|
||||
this.setSession({
|
||||
access: data.access,
|
||||
refresh: data.refresh,
|
||||
user: { username: username.trim() },
|
||||
})
|
||||
await this.fetchMe()
|
||||
return data
|
||||
},
|
||||
|
||||
async fetchMe() {
|
||||
const { data } = await api.get('/v1/auth/me/')
|
||||
this.user = data
|
||||
localStorage.setItem(USER_KEY, JSON.stringify(data))
|
||||
return data
|
||||
},
|
||||
|
||||
async updateProfile({ username, email, currentPassword }) {
|
||||
const payload = { current_password: currentPassword }
|
||||
if (username !== undefined) payload.username = username.trim()
|
||||
if (email !== undefined) payload.email = (email || '').trim()
|
||||
const { data } = await api.patch('/v1/auth/me/', payload)
|
||||
this.user = data
|
||||
localStorage.setItem(USER_KEY, JSON.stringify(data))
|
||||
return data
|
||||
},
|
||||
|
||||
async changePassword({ currentPassword, newPassword }) {
|
||||
const { data } = await api.post('/v1/auth/me/password/', {
|
||||
current_password: currentPassword,
|
||||
new_password: newPassword,
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
logout() {
|
||||
this.accessToken = ''
|
||||
this.refreshToken = ''
|
||||
this.user = null
|
||||
clearSessionStorage()
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export function getStoredAccessToken() {
|
||||
return localStorage.getItem(TOKEN_KEY) || ''
|
||||
}
|
||||
|
||||
export function getStoredRefreshToken() {
|
||||
return localStorage.getItem(REFRESH_KEY) || ''
|
||||
}
|
||||
|
||||
export function setStoredAccessToken(token) {
|
||||
if (token) {
|
||||
localStorage.setItem(TOKEN_KEY, token)
|
||||
} else {
|
||||
localStorage.removeItem(TOKEN_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
export function clearAuthStorage() {
|
||||
clearSessionStorage()
|
||||
}
|
||||
Reference in New Issue
Block a user