mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 20:28:44 +08:00 
			
		
		
		
	增加 oauth2 的 code 的生成与消费的逻辑
This commit is contained in:
		@@ -12,7 +12,7 @@ Content-Type: application/x-www-form-urlencoded
 | 
			
		||||
Authorization: Bearer {{token}}
 | 
			
		||||
tenant-id: {{adminTenentId}}
 | 
			
		||||
 | 
			
		||||
response_type=code&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true
 | 
			
		||||
response_type=code&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true
 | 
			
		||||
 | 
			
		||||
### 请求 /system/oauth2/token + code 接口 => 成功
 | 
			
		||||
POST {{baseUrl}}/system/oauth2/token
 | 
			
		||||
@@ -20,7 +20,7 @@ Content-Type: application/x-www-form-urlencoded
 | 
			
		||||
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
 | 
			
		||||
tenant-id: {{adminTenentId}}
 | 
			
		||||
 | 
			
		||||
grant_type=authorization_code&redirect_uri=https://www.iocoder.cn
 | 
			
		||||
grant_type=authorization_code&redirect_uri=https://www.iocoder.cn&code=189956c07a174588a97157eabef2f93a
 | 
			
		||||
 | 
			
		||||
### 请求 /system/oauth2/token + password 接口 => 成功
 | 
			
		||||
POST {{baseUrl}}/system/oauth2/token
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.auth;
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.auth;
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2CodeDO;
 | 
			
		||||
import org.apache.ibatis.annotations.Mapper;
 | 
			
		||||
 | 
			
		||||
@Mapper
 | 
			
		||||
public interface OAuth2CodeMapper extends BaseMapperX<OAuth2CodeDO> {
 | 
			
		||||
 | 
			
		||||
    default OAuth2CodeDO selectByCode(String code) {
 | 
			
		||||
        return selectOne(OAuth2CodeDO::getCode, code);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.auth;
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.redis.auth;
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.redis.oauth2;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 | 
			
		||||
@@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2Cl
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2ClientMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer;
 | 
			
		||||
import com.google.common.annotations.VisibleForTesting;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,9 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.oauth2;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2CodeDO;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * OAuth2.0 授权码 Service 接口
 | 
			
		||||
 *
 | 
			
		||||
@@ -9,6 +13,27 @@ package cn.iocoder.yudao.module.system.service.oauth2;
 | 
			
		||||
 */
 | 
			
		||||
public interface OAuth2CodeService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建授权码
 | 
			
		||||
     *
 | 
			
		||||
     * 参考 JdbcAuthorizationCodeServices 的 createAuthorizationCode 方法
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId 用户编号
 | 
			
		||||
     * @param userType 用户类型
 | 
			
		||||
     * @param clientId 客户端编号
 | 
			
		||||
     * @param scopes 授权范围
 | 
			
		||||
     * @param redirectUri 重定向 URI
 | 
			
		||||
     * @param state 状态
 | 
			
		||||
     * @return 授权码的信息
 | 
			
		||||
     */
 | 
			
		||||
    OAuth2CodeDO createAuthorizationCode(Long userId, Integer userType, String clientId, List<String> scopes,
 | 
			
		||||
                                         String redirectUri, String state);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 使用授权码
 | 
			
		||||
     *
 | 
			
		||||
     * @param code 授权码
 | 
			
		||||
     */
 | 
			
		||||
    OAuth2CodeDO consumeAuthorizationCode(String code);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.oauth2;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.IdUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2CodeDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2CodeMapper;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CODE_EXPIRE;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CODE_NOT_EXISTS;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * OAuth2.0 授权码 Service 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
@Validated
 | 
			
		||||
public class OAuth2CodeServiceImpl implements OAuth2CodeService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权码的过期时间,默认 5 分钟
 | 
			
		||||
     */
 | 
			
		||||
    private static final Integer TIMEOUT = 5 * 60;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private OAuth2CodeMapper oauth2CodeMapper;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public OAuth2CodeDO createAuthorizationCode(Long userId, Integer userType, String clientId, List<String> scopes,
 | 
			
		||||
                                                String redirectUri, String state) {
 | 
			
		||||
        OAuth2CodeDO codeDO = new OAuth2CodeDO().setCode(generateCode())
 | 
			
		||||
                .setUserId(userId).setUserType(userType)
 | 
			
		||||
                .setClientId(clientId).setScopes(scopes)
 | 
			
		||||
                .setExpiresTime(DateUtils.addDate(Calendar.SECOND, TIMEOUT))
 | 
			
		||||
                .setRedirectUri(redirectUri).setState(state);
 | 
			
		||||
        oauth2CodeMapper.insert(codeDO);
 | 
			
		||||
        return codeDO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public OAuth2CodeDO consumeAuthorizationCode(String code) {
 | 
			
		||||
        OAuth2CodeDO codeDO = oauth2CodeMapper.selectByCode(code);
 | 
			
		||||
        if (codeDO == null) {
 | 
			
		||||
            throw exception(OAUTH2_CODE_NOT_EXISTS);
 | 
			
		||||
        }
 | 
			
		||||
        if (DateUtils.isExpired(codeDO.getExpiresTime())) {
 | 
			
		||||
            throw exception(OAUTH2_CODE_EXPIRE);
 | 
			
		||||
        }
 | 
			
		||||
        oauth2CodeMapper.deleteById(codeDO.getId());
 | 
			
		||||
        return codeDO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String generateCode() {
 | 
			
		||||
        return IdUtil.fastSimpleUUID();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -15,8 +15,6 @@ import javax.annotation.Resource;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_GRANT_CODE_NOT_EXISTS;
 | 
			
		||||
import static java.util.Collections.singletonList;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * OAuth2 授予 Service 实现类
 | 
			
		||||
@@ -29,6 +27,8 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private OAuth2TokenService oauth2TokenService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private OAuth2CodeService oauth2CodeService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AdminAuthService adminAuthService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -41,18 +41,15 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService {
 | 
			
		||||
    public String grantAuthorizationCodeForCode(Long userId, Integer userType,
 | 
			
		||||
                                                String clientId, List<String> scopes,
 | 
			
		||||
                                                String redirectUri, String state) {
 | 
			
		||||
        return "test";
 | 
			
		||||
        return oauth2CodeService.createAuthorizationCode(userId, userType, clientId, scopes,
 | 
			
		||||
                redirectUri, state).getCode();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public OAuth2AccessTokenDO grantAuthorizationCodeForAccessToken(String clientId, String code,
 | 
			
		||||
                                                                    String redirectUri, String state) {
 | 
			
		||||
        // TODO 消费 code
 | 
			
		||||
        OAuth2CodeDO codeDO = new OAuth2CodeDO().setClientId("default").setRedirectUri("https://www.iocoder.cn").setState("")
 | 
			
		||||
                .setUserId(1L).setUserType(2).setScopes(singletonList("user_info"));
 | 
			
		||||
        if (codeDO == null) {
 | 
			
		||||
            throw exception(OAUTH2_GRANT_CODE_NOT_EXISTS);
 | 
			
		||||
        }
 | 
			
		||||
        OAuth2CodeDO codeDO = oauth2CodeService.consumeAuthorizationCode(code);
 | 
			
		||||
        Assert.notNull(codeDO, "授权码不能为空"); // 防御性编程
 | 
			
		||||
        // 校验 clientId 是否匹配
 | 
			
		||||
        if (!StrUtil.equals(clientId, codeDO.getClientId())) {
 | 
			
		||||
            throw exception(ErrorCodeConstants.OAUTH2_GRANT_CLIENT_ID_MISMATCH);
 | 
			
		||||
 
 | 
			
		||||
@@ -11,9 +11,9 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2Acc
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2RefreshTokenDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2AccessTokenMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2RefreshTokenMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.redis.auth.OAuth2AccessTokenRedisDAO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.transaction.annotation.Transactional;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user