houzhongjian
2024-09-14 818a0170d8f2950d52cc7300a302356bbc523236
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.system.service.oauth2;
H 2
3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert;
5 import com.iailab.framework.common.util.date.DateUtils;
6 import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
7 import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
8 import com.iailab.module.system.dal.mysql.oauth2.OAuth2ApproveMapper;
9 import com.google.common.annotations.VisibleForTesting;
10 import org.springframework.stereotype.Service;
11 import org.springframework.transaction.annotation.Transactional;
12 import org.springframework.validation.annotation.Validated;
13
14 import javax.annotation.Resource;
15 import java.time.LocalDateTime;
16 import java.util.*;
17
18 import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet;
19
20 /**
21  * OAuth2 批准 Service 实现类
22  *
23  * @author iailab
24  */
25 @Service
26 @Validated
27 public class OAuth2ApproveServiceImpl implements OAuth2ApproveService {
28
29     /**
30      * 批准的过期时间,默认 30 天
31      */
32     private static final Integer TIMEOUT = 30 * 24 * 60 * 60; // 单位:秒
33
34     @Resource
35     private OAuth2ClientService oauth2ClientService;
36
37     @Resource
38     private OAuth2ApproveMapper oauth2ApproveMapper;
39
40     @Override
41     @Transactional
42     public boolean checkForPreApproval(Long userId, Integer userType, String clientId, Collection<String> requestedScopes) {
43         // 第一步,基于 Client 的自动授权计算,如果 scopes 都在自动授权中,则返回 true 通过
44         OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId);
45         Assert.notNull(clientDO, "客户端不能为空"); // 防御性编程
46         if (CollUtil.containsAll(clientDO.getAutoApproveScopes(), requestedScopes)) {
47             // gh-877 - if all scopes are auto approved, approvals still need to be added to the approval store.
48             LocalDateTime expireTime = LocalDateTime.now().plusSeconds(TIMEOUT);
49             for (String scope : requestedScopes) {
50                 saveApprove(userId, userType, clientId, scope, true, expireTime);
51             }
52             return true;
53         }
54
55         // 第二步,算上用户已经批准的授权。如果 scopes 都包含,则返回 true
56         List<OAuth2ApproveDO> approveDOs = getApproveList(userId, userType, clientId);
57         Set<String> scopes = convertSet(approveDOs, OAuth2ApproveDO::getScope,
58                 OAuth2ApproveDO::getApproved); // 只保留未过期的 + 同意的
59         return CollUtil.containsAll(scopes, requestedScopes);
60     }
61
62     @Override
63     @Transactional
64     public boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map<String, Boolean> requestedScopes) {
65         // 如果 requestedScopes 为空,说明没有要求,则返回 true 通过
66         if (CollUtil.isEmpty(requestedScopes)) {
67             return true;
68         }
69
70         // 更新批准的信息
71         boolean success = false; // 需要至少有一个同意
72         LocalDateTime expireTime = LocalDateTime.now().plusSeconds(TIMEOUT);
73         for (Map.Entry<String, Boolean> entry : requestedScopes.entrySet()) {
74             if (entry.getValue()) {
75                 success = true;
76             }
77             saveApprove(userId, userType, clientId, entry.getKey(), entry.getValue(), expireTime);
78         }
79         return success;
80     }
81
82     @Override
83     public List<OAuth2ApproveDO> getApproveList(Long userId, Integer userType, String clientId) {
84         List<OAuth2ApproveDO> approveDOs = oauth2ApproveMapper.selectListByUserIdAndUserTypeAndClientId(
85                 userId, userType, clientId);
86         approveDOs.removeIf(o -> DateUtils.isExpired(o.getExpiresTime()));
87         return approveDOs;
88     }
89
90     @VisibleForTesting
91     void saveApprove(Long userId, Integer userType, String clientId,
92                      String scope, Boolean approved, LocalDateTime expireTime) {
93         // 先更新
94         OAuth2ApproveDO approveDO = new OAuth2ApproveDO().setUserId(userId).setUserType(userType)
95                 .setClientId(clientId).setScope(scope).setApproved(approved).setExpiresTime(expireTime);
96         if (oauth2ApproveMapper.update(approveDO) == 1) {
97             return;
98         }
99         // 失败,则说明不存在,进行更新
100         oauth2ApproveMapper.insert(approveDO);
101     }
102
103 }