mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 10:00:30 +08:00
feat(m11): add v-permission directive and button-level permission codes
This commit is contained in:
+32
-5
@@ -58,12 +58,39 @@ public class AuthController {
|
|||||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "invalid credentials");
|
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "invalid credentials");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> permissions = new java.util.ArrayList<>();
|
||||||
|
switch(role) {
|
||||||
|
case "SYS_ADMIN":
|
||||||
|
permissions.add("*:*");
|
||||||
|
break;
|
||||||
|
case "SALES":
|
||||||
|
permissions.add("customer:*");
|
||||||
|
permissions.add("project:*");
|
||||||
|
permissions.add("contract:*");
|
||||||
|
permissions.add("delivery:read");
|
||||||
|
break;
|
||||||
|
case "DELIVERY":
|
||||||
|
permissions.add("delivery:*");
|
||||||
|
permissions.add("device:*");
|
||||||
|
break;
|
||||||
|
case "LICENSE_OPS":
|
||||||
|
permissions.add("license:*");
|
||||||
|
permissions.add("callback:*");
|
||||||
|
permissions.add("todo:*");
|
||||||
|
permissions.add("device:read");
|
||||||
|
permissions.add("integration:read");
|
||||||
|
permissions.add("report:callback");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
String token = jwtService.createToken(user, displayName, List.of(role));
|
String token = jwtService.createToken(user, displayName, List.of(role));
|
||||||
return Map.of(
|
java.util.Map<String, Object> result = new java.util.LinkedHashMap<>();
|
||||||
"token", token,
|
result.put("token", token);
|
||||||
"tokenType", "Bearer",
|
result.put("tokenType", "Bearer");
|
||||||
"roles", List.of(role),
|
result.put("roles", List.of(role));
|
||||||
"displayName", displayName);
|
result.put("displayName", displayName);
|
||||||
|
result.put("permissions", permissions);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/change-password")
|
@PostMapping("/change-password")
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { useAuthStore } from '../stores/auth'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted(el, binding) {
|
||||||
|
const auth = useAuthStore()
|
||||||
|
const requiredPermission = binding.value
|
||||||
|
|
||||||
|
if (!requiredPermission) return
|
||||||
|
|
||||||
|
const userPermissions = auth.permissions || []
|
||||||
|
|
||||||
|
const hasPermission = userPermissions.some(p => {
|
||||||
|
if (typeof p === 'string') {
|
||||||
|
if (requiredPermission.endsWith(':*')) {
|
||||||
|
const prefix = requiredPermission.slice(0, -2)
|
||||||
|
return p.startsWith(prefix)
|
||||||
|
}
|
||||||
|
return p === requiredPermission || p === '*:*'
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!hasPermission) {
|
||||||
|
el.parentNode?.removeChild(el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import axios from "axios";
|
|||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
import { useAuthStore } from "./stores/auth";
|
import { useAuthStore } from "./stores/auth";
|
||||||
|
import permission from "./directives/permission";
|
||||||
|
|
||||||
// 开发环境始终使用相对路径,以便 Vite 将 /api 代理到后端;误设 VITE_API_BASE 时否则会直连并常出现跨域或连错环境。
|
// 开发环境始终使用相对路径,以便 Vite 将 /api 代理到后端;误设 VITE_API_BASE 时否则会直连并常出现跨域或连错环境。
|
||||||
const apiBaseRaw =
|
const apiBaseRaw =
|
||||||
@@ -38,4 +39,5 @@ axios.interceptors.response.use(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.directive("permission", permission);
|
||||||
app.use(router).use(ElementPlus).mount("#app");
|
app.use(router).use(ElementPlus).mount("#app");
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export const useAuthStore = defineStore("auth", {
|
|||||||
token: localStorage.getItem(TOKEN_KEY) || "",
|
token: localStorage.getItem(TOKEN_KEY) || "",
|
||||||
displayName: "",
|
displayName: "",
|
||||||
roles: [],
|
roles: [],
|
||||||
|
permissions: [],
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
hasAnyRole: (state) => {
|
hasAnyRole: (state) => {
|
||||||
@@ -24,6 +25,7 @@ export const useAuthStore = defineStore("auth", {
|
|||||||
this.token = data.token;
|
this.token = data.token;
|
||||||
this.displayName = data.displayName || username;
|
this.displayName = data.displayName || username;
|
||||||
this.roles = data.roles || [];
|
this.roles = data.roles || [];
|
||||||
|
this.permissions = data.permissions || [];
|
||||||
localStorage.setItem(TOKEN_KEY, this.token);
|
localStorage.setItem(TOKEN_KEY, this.token);
|
||||||
axios.defaults.headers.common.Authorization = `Bearer ${this.token}`;
|
axios.defaults.headers.common.Authorization = `Bearer ${this.token}`;
|
||||||
},
|
},
|
||||||
@@ -31,6 +33,7 @@ export const useAuthStore = defineStore("auth", {
|
|||||||
this.token = "";
|
this.token = "";
|
||||||
this.displayName = "";
|
this.displayName = "";
|
||||||
this.roles = [];
|
this.roles = [];
|
||||||
|
this.permissions = [];
|
||||||
localStorage.removeItem(TOKEN_KEY);
|
localStorage.removeItem(TOKEN_KEY);
|
||||||
delete axios.defaults.headers.common.Authorization;
|
delete axios.defaults.headers.common.Authorization;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
@keyup.enter="load"
|
@keyup.enter="load"
|
||||||
/>
|
/>
|
||||||
<el-button type="primary" :loading="loading" @click="load">查询</el-button>
|
<el-button type="primary" :loading="loading" @click="load">查询</el-button>
|
||||||
<el-button type="success" @click="openCreate">新建客户</el-button>
|
<el-button type="success" v-permission="'customer:rw'" @click="openCreate">新建客户</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
<el-table-column label="操作" width="200" fixed="right">
|
<el-table-column label="操作" width="200" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" link @click="goDetail(row.id)">详情</el-button>
|
<el-button type="primary" link @click="goDetail(row.id)">详情</el-button>
|
||||||
<el-button type="primary" link @click="openEdit(row)">编辑</el-button>
|
<el-button type="primary" link v-permission="'customer:rw'" @click="openEdit(row)">编辑</el-button>
|
||||||
<el-button type="danger" link @click="onDelete(row)">删除</el-button>
|
<el-button type="danger" link v-permission="'customer:delete'" @click="onDelete(row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
@keyup.enter="load"
|
@keyup.enter="load"
|
||||||
/>
|
/>
|
||||||
<el-button type="primary" :loading="loading" @click="load">查询</el-button>
|
<el-button type="primary" :loading="loading" @click="load">查询</el-button>
|
||||||
<el-button type="success" @click="goNew">新建许可 SN</el-button>
|
<el-button type="success" v-permission="'license:sn:rw'" @click="goNew">新建许可 SN</el-button>
|
||||||
<el-button @click="batchDialogVisible = true">批量导入</el-button>
|
<el-button v-permission="'license:sn:rw'" @click="batchDialogVisible = true">批量导入</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user