选煤厂安全管理系统前端代码
houzhongjian
2024-11-25 37b2044f04a09e89f82f8484279b5f06b7194481
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<template>
  <div v-show="ssoVisible" class="form-cont">
    <!-- 应用名 -->
    <LoginFormTitle style="width: 100%" />
    <el-tabs class="form" style="float: none" value="uname">
      <el-tab-pane :label="client.name" name="uname" />
    </el-tabs>
    <div>
      <el-form :model="formData" class="login-form">
        <!-- 授权范围的选择 -->
        此第三方应用请求获得以下权限:
        <br/>
        <br/>
        <el-form-item prop="scopes">
          <el-checkbox-group v-model="formData.scopes">
            <el-checkbox
              v-for="scope in queryParams.scopes"
              :key="scope"
              :label="scope"
              style="display: block; margin-bottom: -10px"
            >
              {{ formatScope(scope) }}
            </el-checkbox>
          </el-checkbox-group>
        </el-form-item>
        <!-- 下方的登录按钮 -->
        <el-form-item class="w-1/1">
          <el-button
            :loading="formLoading"
            class="w-6/10"
            type="primary"
            @click.prevent="handleAuthorize(true)"
          >
            <span v-if="!formLoading">同意授权</span>
            <span v-else>授 权 中...</span>
          </el-button>
          <el-button class="w-3/10" @click.prevent="handleAuthorize(false)">拒绝</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>
<script lang="ts" setup>
import LoginFormTitle from './LoginFormTitle.vue'
import * as OAuth2Api from '@/api/login/oauth2'
import { LoginStateEnum, useLoginState } from './useLogin'
import type { RouteLocationNormalizedLoaded } from 'vue-router'
 
defineOptions({ name: 'SSOLogin' })
 
const route = useRoute() // 路由
const { currentRoute } = useRouter() // 路由
const { getLoginState, setLoginState } = useLoginState()
 
const client = ref({
  // 客户端信息
  name: '',
  logo: ''
})
interface queryType {
  responseType: string
  clientId: string
  redirectUri: string
  state: string
  scopes: string[]
}
const queryParams = reactive<queryType>({
  // URL 上的 client_id、scope 等参数
  responseType: '',
  clientId: '',
  redirectUri: '',
  state: '',
  scopes: [] // 优先从 query 参数获取;如果未传递,从后端获取
})
const ssoVisible = computed(() => unref(getLoginState) === LoginStateEnum.SSO) // 是否展示 SSO 登录的表单
interface formType {
  scopes: string[]
}
const formData = reactive<formType>({
  scopes: [] // 已选中的 scope 数组
})
const formLoading = ref(false) // 表单是否提交中
 
/** 初始化授权信息 */
const init = async () => {
  // 防止在没有登录的情况下循环弹窗
  if (typeof route.query.client_id === 'undefined') return
  // 解析参数
  // 例如说【自动授权不通过】:client_id=default&redirect_uri=https%3A%2F%2Fwww.xxxx.cn&response_type=code&scope=user.read%20user.write
  // 例如说【自动授权通过】:client_id=default&redirect_uri=https%3A%2F%2Fwww.xxxx.cn&response_type=code&scope=user.read
  queryParams.responseType = route.query.response_type as string
  queryParams.clientId = route.query.client_id as string
  queryParams.redirectUri = route.query.redirect_uri as string
  queryParams.state = route.query.state as string
  if (route.query.scope) {
    queryParams.scopes = (route.query.scope as string).split(' ')
  }
 
  // 如果有 scope 参数,先执行一次自动授权,看看是否之前都授权过了。
  if (queryParams.scopes.length > 0) {
    const data = await doAuthorize(true, queryParams.scopes, [])
    if (data) {
      location.href = data
      return
    }
  }
 
  // 获取授权页的基本信息
  const data = await OAuth2Api.getAuthorize(queryParams.clientId)
  client.value = data.client
  // 解析 scope
  let scopes
  // 1.1 如果 params.scope 非空,则过滤下返回的 scopes
  if (queryParams.scopes.length > 0) {
    scopes = []
    for (const scope of data.scopes) {
      if (queryParams.scopes.indexOf(scope.key) >= 0) {
        scopes.push(scope)
      }
    }
    // 1.2 如果 params.scope 为空,则使用返回的 scopes 设置它
  } else {
    scopes = data.scopes
    for (const scope of scopes) {
      queryParams.scopes.push(scope.key)
    }
  }
  // 生成已选中的 checkedScopes
  for (const scope of scopes) {
    if (scope.value) {
      formData.scopes.push(scope.key)
    }
  }
}
 
/** 处理授权的提交 */
const handleAuthorize = async (approved) => {
  // 计算 checkedScopes + uncheckedScopes
  let checkedScopes
  let uncheckedScopes
  if (approved) {
    // 同意授权,按照用户的选择
    checkedScopes = formData.scopes
    uncheckedScopes = queryParams.scopes.filter((item) => checkedScopes.indexOf(item) === -1)
  } else {
    // 拒绝,则都是取消
    checkedScopes = []
    uncheckedScopes = queryParams.scopes
  }
  // 提交授权的请求
  formLoading.value = true
  try {
    const data = await doAuthorize(false, checkedScopes, uncheckedScopes)
    if (!data) {
      return
    }
    location.href = data
  } finally {
    formLoading.value = false
  }
}
 
/** 调用授权 API 接口 */
const doAuthorize = (autoApprove, checkedScopes, uncheckedScopes) => {
  return OAuth2Api.authorize(
    queryParams.responseType,
    queryParams.clientId,
    queryParams.redirectUri,
    queryParams.state,
    autoApprove,
    checkedScopes,
    uncheckedScopes
  )
}
 
/** 格式化 scope 文本 */
const formatScope = (scope) => {
  // 格式化 scope 授权范围,方便用户理解。
  // 这里仅仅是一个 demo,可以考虑录入到字典数据中,例如说字典类型 "system_oauth2_scope",它的每个 scope 都是一条字典数据。
  switch (scope) {
    case 'user.read':
      return '访问你的个人信息'
    case 'user.write':
      return '修改你的个人信息'
    default:
      return scope
  }
}
 
/** 监听当前路由为 SSOLogin 时,进行数据的初始化 */
watch(
  () => currentRoute.value,
  (route: RouteLocationNormalizedLoaded) => {
    if (route.name === 'SSOLogin') {
      setLoginState(LoginStateEnum.SSO)
      init()
    }
  },
  { immediate: true }
)
</script>