houzhongjian
2024-07-11 759b1c71011abd6b58c37d2566f3f3c208c2f1b2
提交 | 用户 | 时间
759b1c 1 <template>
H 2   <div class="container">
3     <div class="logo"></div>
4     <!-- 登录区域 -->
5     <div class="content">
6       <!-- 配图 -->
7       <div class="pic"></div>
8       <!-- 表单 -->
9       <div class="field">
10         <!-- [移动端]标题 -->
11         <h2 class="mobile-title">
12           <h3 class="title">工业互联网平台</h3>
13         </h2>
14
15         <!-- 表单 -->
16         <div class="form-cont">
17           <el-tabs class="form" style=" float:none;" value="uname">
18             <el-tab-pane :label="'三方授权(' + client.name + ')'" name="uname">
19             </el-tab-pane>
20           </el-tabs>
21           <div>
22             <el-form ref="loginForm" :model="loginForm" class="login-form">
23               <!-- 授权范围的选择 -->
24               此第三方应用请求获得以下权限:
25               <el-form-item prop="scopes">
26                 <el-checkbox-group v-model="loginForm.scopes">
27                   <el-checkbox v-for="scope in params.scopes" :label="scope" :key="scope"
28                                style="display: block; margin-bottom: -10px;">{{formatScope(scope)}}</el-checkbox>
29                 </el-checkbox-group>
30               </el-form-item>
31               <!-- 下方的登录按钮 -->
32               <el-form-item style="width:100%;">
33                 <el-button :loading="loading" size="medium" type="primary" style="width:60%;"
34                            @click.native.prevent="handleAuthorize(true)">
35                   <span v-if="!loading">同意授权</span>
36                   <span v-else>授 权 中...</span>
37                 </el-button>
38                 <el-button size="medium" style="width:36%"
39                            @click.native.prevent="handleAuthorize(false)">拒绝</el-button>
40               </el-form-item>
41             </el-form>
42           </div>
43         </div>
44       </div>
45     </div>
46     <!-- footer -->
47     <div class="footer">
48       Copyright © 2020-2022 iocoder.cn All Rights Reserved.
49     </div>
50   </div>
51 </template>
52
53 <script>
54 import {authorize, getAuthorize} from "@/api/login";
55
56 export default {
57   name: "Login",
58   data() {
59     return {
60       loginForm: {
61         scopes: [], // 已选中的 scope 数组
62       },
63       params: { // URL 上的 client_id、scope 等参数
64         responseType: undefined,
65         clientId: undefined,
66         redirectUri: undefined,
67         state: undefined,
68         scopes: [], // 优先从 query 参数获取;如果未传递,从后端获取
69       },
70       client: { // 客户端信息
71         name: '',
72         logo: '',
73       },
74       loading: false
75     };
76   },
77   created() {
78     // 解析参数
79     // 例如说【自动授权不通过】:client_id=default&redirect_uri=https%3A%2F%2Fwww.baidu.com&response_type=code&scope=user.read%20user.write
80     // 例如说【自动授权通过】:client_id=default&redirect_uri=https%3A%2F%2Fwww.baidu.com&response_type=code&scope=user.read
81     this.params.responseType = this.$route.query.response_type
82     this.params.clientId = this.$route.query.client_id
83     this.params.redirectUri = this.$route.query.redirect_uri
84     this.params.state = this.$route.query.state
85     if (this.$route.query.scope) {
86       this.params.scopes = this.$route.query.scope.split(' ')
87     }
88
89     // 如果有 scope 参数,先执行一次自动授权,看看是否之前都授权过了。
90     if (this.params.scopes.length > 0) {
91       this.doAuthorize(true, this.params.scopes, []).then(res => {
92         const href = res.data
93         if (!href) {
94           console.log('自动授权未通过!')
95           return;
96         }
97         location.href = href
98       })
99     }
100
101     // 获取授权页的基本信息
102     getAuthorize(this.params.clientId).then(res => {
103       this.client = res.data.client
104       // 解析 scope
105       let scopes
106       // 1.1 如果 params.scope 非空,则过滤下返回的 scopes
107       if (this.params.scopes.length > 0) {
108         scopes = []
109         for (const scope of res.data.scopes) {
110           if (this.params.scopes.indexOf(scope.key) >= 0) {
111             scopes.push(scope)
112           }
113         }
114       // 1.2 如果 params.scope 为空,则使用返回的 scopes 设置它
115       } else {
116         scopes = res.data.scopes
117         for (const scope of scopes) {
118           this.params.scopes.push(scope.key)
119         }
120       }
121       // 生成已选中的 checkedScopes
122       for (const scope of scopes) {
123         if (scope.value) {
124           this.loginForm.scopes.push(scope.key)
125         }
126       }
127     })
128   },
129   methods: {
130     handleAuthorize(approved) {
131       this.$refs.loginForm.validate(valid => {
132         if (!valid) {
133           return
134         }
135         this.loading = true
136         // 计算 checkedScopes + uncheckedScopes
137         let checkedScopes;
138         let uncheckedScopes;
139         if (approved) { // 同意授权,按照用户的选择
140           checkedScopes = this.loginForm.scopes
141           uncheckedScopes = this.params.scopes.filter(item => checkedScopes.indexOf(item) === -1)
142         } else { // 拒绝,则都是取消
143           checkedScopes = []
144           uncheckedScopes = this.params.scopes
145         }
146         // 提交授权的请求
147         this.doAuthorize(false, checkedScopes, uncheckedScopes).then(res => {
148           const href = res.data
149           if (!href) {
150             return;
151           }
152           location.href = href
153         }).finally(() => {
154           this.loading = false
155         })
156       })
157     },
158     doAuthorize(autoApprove, checkedScopes, uncheckedScopes) {
159       return authorize(this.params.responseType, this.params.clientId, this.params.redirectUri, this.params.state,
160           autoApprove, checkedScopes, uncheckedScopes)
161     },
162     formatScope(scope) {
163       // 格式化 scope 授权范围,方便用户理解。
164       // 这里仅仅是一个 demo,可以考虑录入到字典数据中,例如说字典类型 "system_oauth2_scope",它的每个 scope 都是一条字典数据。
165       switch (scope) {
166         case 'user.read': return '访问你的个人信息'
167         case 'user.write': return '修改你的个人信息'
168         default: return scope
169       }
170     }
171   }
172 };
173 </script>
174 <style lang="scss" scoped>
175 @import "~@/assets/styles/login.scss";
176 .oauth-login {
177   display: flex;
178   align-items: center;
179   cursor:pointer;
180 }
181 .oauth-login-item {
182   display: flex;
183   align-items: center;
184   margin-right: 10px;
185 }
186 .oauth-login-item img {
187   height: 25px;
188   width: 25px;
189 }
190 .oauth-login-item span:hover {
191   text-decoration: underline red;
192   color: red;
193 }
194 </style>