Commit 60bb8dd29ca970cfed61765812ff372e313ad080
1 parent
feff5aba
增加 oauth2 的 code 的生成与消费的逻辑
Showing
13 changed files
with
128 additions
and
24 deletions
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
| ... | ... | @@ -133,9 +133,13 @@ public interface ErrorCodeConstants { |
| 133 | 133 | ErrorCode OAUTH2_CLIENT_CLIENT_SECRET_ERROR = new ErrorCode(1002020006, "无效 client_secret: {}"); |
| 134 | 134 | |
| 135 | 135 | // ========== OAuth2 授权 1002021000 ========= |
| 136 | - ErrorCode OAUTH2_GRANT_CLIENT_ID_MISMATCH = new ErrorCode(1002020000, "client_id 不匹配"); | |
| 137 | - ErrorCode OAUTH2_GRANT_REDIRECT_URI_MISMATCH = new ErrorCode(1002020001, "redirect_uri 不匹配"); | |
| 138 | - ErrorCode OAUTH2_GRANT_STATE_MISMATCH = new ErrorCode(1002020002, "state 不匹配"); | |
| 139 | - ErrorCode OAUTH2_GRANT_CODE_NOT_EXISTS = new ErrorCode(1002020003, "code 不存在"); | |
| 136 | + ErrorCode OAUTH2_GRANT_CLIENT_ID_MISMATCH = new ErrorCode(1002021000, "client_id 不匹配"); | |
| 137 | + ErrorCode OAUTH2_GRANT_REDIRECT_URI_MISMATCH = new ErrorCode(1002021001, "redirect_uri 不匹配"); | |
| 138 | + ErrorCode OAUTH2_GRANT_STATE_MISMATCH = new ErrorCode(1002021002, "state 不匹配"); | |
| 139 | + ErrorCode OAUTH2_GRANT_CODE_NOT_EXISTS = new ErrorCode(1002021003, "code 不存在"); | |
| 140 | + | |
| 141 | + // ========== OAuth2 授权 1002022000 ========= | |
| 142 | + ErrorCode OAUTH2_CODE_NOT_EXISTS = new ErrorCode(1002022000, "code 不存在"); | |
| 143 | + ErrorCode OAUTH2_CODE_EXPIRE = new ErrorCode(1002022000, "code 已过期"); | |
| 140 | 144 | |
| 141 | 145 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http
| ... | ... | @@ -12,7 +12,7 @@ Content-Type: application/x-www-form-urlencoded |
| 12 | 12 | Authorization: Bearer {{token}} |
| 13 | 13 | tenant-id: {{adminTenentId}} |
| 14 | 14 | |
| 15 | -response_type=code&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true | |
| 15 | +response_type=code&client_id=default&scope={"user.read": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true | |
| 16 | 16 | |
| 17 | 17 | ### 请求 /system/oauth2/token + code 接口 => 成功 |
| 18 | 18 | POST {{baseUrl}}/system/oauth2/token |
| ... | ... | @@ -20,7 +20,7 @@ Content-Type: application/x-www-form-urlencoded |
| 20 | 20 | Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== |
| 21 | 21 | tenant-id: {{adminTenentId}} |
| 22 | 22 | |
| 23 | -grant_type=authorization_code&redirect_uri=https://www.iocoder.cn | |
| 23 | +grant_type=authorization_code&redirect_uri=https://www.iocoder.cn&code=189956c07a174588a97157eabef2f93a | |
| 24 | 24 | |
| 25 | 25 | ### 请求 /system/oauth2/token + password 接口 => 成功 |
| 26 | 26 | POST {{baseUrl}}/system/oauth2/token | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2AccessTokenMapper.java renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2ClientMapper.java renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2ClientMapper.java
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2CodeMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.dal.mysql.oauth2; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 4 | +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2CodeDO; | |
| 5 | +import org.apache.ibatis.annotations.Mapper; | |
| 6 | + | |
| 7 | +@Mapper | |
| 8 | +public interface OAuth2CodeMapper extends BaseMapperX<OAuth2CodeDO> { | |
| 9 | + | |
| 10 | + default OAuth2CodeDO selectByCode(String code) { | |
| 11 | + return selectOne(OAuth2CodeDO::getCode, code); | |
| 12 | + } | |
| 13 | + | |
| 14 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/auth/OAuth2RefreshTokenMapper.java renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2RefreshTokenMapper.java
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/auth/OAuth2AccessTokenRedisDAO.java renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java
| ... | ... | @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2Cl |
| 11 | 11 | import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO; |
| 12 | 12 | import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert; |
| 13 | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; |
| 14 | -import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2ClientMapper; | |
| 14 | +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper; | |
| 15 | 15 | import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer; |
| 16 | 16 | import com.google.common.annotations.VisibleForTesting; |
| 17 | 17 | import lombok.Getter; | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeService.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.oauth2; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2CodeDO; | |
| 4 | + | |
| 5 | +import java.util.List; | |
| 6 | + | |
| 3 | 7 | /** |
| 4 | 8 | * OAuth2.0 授权码 Service 接口 |
| 5 | 9 | * |
| ... | ... | @@ -9,6 +13,27 @@ package cn.iocoder.yudao.module.system.service.oauth2; |
| 9 | 13 | */ |
| 10 | 14 | public interface OAuth2CodeService { |
| 11 | 15 | |
| 16 | + /** | |
| 17 | + * 创建授权码 | |
| 18 | + * | |
| 19 | + * 参考 JdbcAuthorizationCodeServices 的 createAuthorizationCode 方法 | |
| 20 | + * | |
| 21 | + * @param userId 用户编号 | |
| 22 | + * @param userType 用户类型 | |
| 23 | + * @param clientId 客户端编号 | |
| 24 | + * @param scopes 授权范围 | |
| 25 | + * @param redirectUri 重定向 URI | |
| 26 | + * @param state 状态 | |
| 27 | + * @return 授权码的信息 | |
| 28 | + */ | |
| 29 | + OAuth2CodeDO createAuthorizationCode(Long userId, Integer userType, String clientId, List<String> scopes, | |
| 30 | + String redirectUri, String state); | |
| 12 | 31 | |
| 32 | + /** | |
| 33 | + * 使用授权码 | |
| 34 | + * | |
| 35 | + * @param code 授权码 | |
| 36 | + */ | |
| 37 | + OAuth2CodeDO consumeAuthorizationCode(String code); | |
| 13 | 38 | |
| 14 | 39 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.service.oauth2; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.IdUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.date.DateUtils; | |
| 5 | +import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2CodeDO; | |
| 6 | +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2CodeMapper; | |
| 7 | +import org.springframework.stereotype.Service; | |
| 8 | +import org.springframework.validation.annotation.Validated; | |
| 9 | + | |
| 10 | +import javax.annotation.Resource; | |
| 11 | +import java.util.Calendar; | |
| 12 | +import java.util.List; | |
| 13 | + | |
| 14 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 15 | +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CODE_EXPIRE; | |
| 16 | +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CODE_NOT_EXISTS; | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * OAuth2.0 授权码 Service 实现类 | |
| 20 | + * | |
| 21 | + * @author 芋道源码 | |
| 22 | + */ | |
| 23 | +@Service | |
| 24 | +@Validated | |
| 25 | +public class OAuth2CodeServiceImpl implements OAuth2CodeService { | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 授权码的过期时间,默认 5 分钟 | |
| 29 | + */ | |
| 30 | + private static final Integer TIMEOUT = 5 * 60; | |
| 31 | + | |
| 32 | + @Resource | |
| 33 | + private OAuth2CodeMapper oauth2CodeMapper; | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public OAuth2CodeDO createAuthorizationCode(Long userId, Integer userType, String clientId, List<String> scopes, | |
| 37 | + String redirectUri, String state) { | |
| 38 | + OAuth2CodeDO codeDO = new OAuth2CodeDO().setCode(generateCode()) | |
| 39 | + .setUserId(userId).setUserType(userType) | |
| 40 | + .setClientId(clientId).setScopes(scopes) | |
| 41 | + .setExpiresTime(DateUtils.addDate(Calendar.SECOND, TIMEOUT)) | |
| 42 | + .setRedirectUri(redirectUri).setState(state); | |
| 43 | + oauth2CodeMapper.insert(codeDO); | |
| 44 | + return codeDO; | |
| 45 | + } | |
| 46 | + | |
| 47 | + @Override | |
| 48 | + public OAuth2CodeDO consumeAuthorizationCode(String code) { | |
| 49 | + OAuth2CodeDO codeDO = oauth2CodeMapper.selectByCode(code); | |
| 50 | + if (codeDO == null) { | |
| 51 | + throw exception(OAUTH2_CODE_NOT_EXISTS); | |
| 52 | + } | |
| 53 | + if (DateUtils.isExpired(codeDO.getExpiresTime())) { | |
| 54 | + throw exception(OAUTH2_CODE_EXPIRE); | |
| 55 | + } | |
| 56 | + oauth2CodeMapper.deleteById(codeDO.getId()); | |
| 57 | + return codeDO; | |
| 58 | + } | |
| 59 | + | |
| 60 | + private static String generateCode() { | |
| 61 | + return IdUtil.fastSimpleUUID(); | |
| 62 | + } | |
| 63 | + | |
| 64 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java
| ... | ... | @@ -15,8 +15,6 @@ import javax.annotation.Resource; |
| 15 | 15 | import java.util.List; |
| 16 | 16 | |
| 17 | 17 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 18 | -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_GRANT_CODE_NOT_EXISTS; | |
| 19 | -import static java.util.Collections.singletonList; | |
| 20 | 18 | |
| 21 | 19 | /** |
| 22 | 20 | * OAuth2 授予 Service 实现类 |
| ... | ... | @@ -29,6 +27,8 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService { |
| 29 | 27 | @Resource |
| 30 | 28 | private OAuth2TokenService oauth2TokenService; |
| 31 | 29 | @Resource |
| 30 | + private OAuth2CodeService oauth2CodeService; | |
| 31 | + @Resource | |
| 32 | 32 | private AdminAuthService adminAuthService; |
| 33 | 33 | |
| 34 | 34 | @Override |
| ... | ... | @@ -41,18 +41,15 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService { |
| 41 | 41 | public String grantAuthorizationCodeForCode(Long userId, Integer userType, |
| 42 | 42 | String clientId, List<String> scopes, |
| 43 | 43 | String redirectUri, String state) { |
| 44 | - return "test"; | |
| 44 | + return oauth2CodeService.createAuthorizationCode(userId, userType, clientId, scopes, | |
| 45 | + redirectUri, state).getCode(); | |
| 45 | 46 | } |
| 46 | 47 | |
| 47 | 48 | @Override |
| 48 | 49 | public OAuth2AccessTokenDO grantAuthorizationCodeForAccessToken(String clientId, String code, |
| 49 | 50 | String redirectUri, String state) { |
| 50 | - // TODO 消费 code | |
| 51 | - OAuth2CodeDO codeDO = new OAuth2CodeDO().setClientId("default").setRedirectUri("https://www.iocoder.cn").setState("") | |
| 52 | - .setUserId(1L).setUserType(2).setScopes(singletonList("user_info")); | |
| 53 | - if (codeDO == null) { | |
| 54 | - throw exception(OAUTH2_GRANT_CODE_NOT_EXISTS); | |
| 55 | - } | |
| 51 | + OAuth2CodeDO codeDO = oauth2CodeService.consumeAuthorizationCode(code); | |
| 52 | + Assert.notNull(codeDO, "授权码不能为空"); // 防御性编程 | |
| 56 | 53 | // 校验 clientId 是否匹配 |
| 57 | 54 | if (!StrUtil.equals(clientId, codeDO.getClientId())) { |
| 58 | 55 | throw exception(ErrorCodeConstants.OAUTH2_GRANT_CLIENT_ID_MISMATCH); | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImpl.java
| ... | ... | @@ -11,9 +11,9 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2Acc |
| 11 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; |
| 12 | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; |
| 13 | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2RefreshTokenDO; |
| 14 | -import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2AccessTokenMapper; | |
| 15 | -import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2RefreshTokenMapper; | |
| 16 | -import cn.iocoder.yudao.module.system.dal.redis.auth.OAuth2AccessTokenRedisDAO; | |
| 14 | +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper; | |
| 15 | +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper; | |
| 16 | +import cn.iocoder.yudao.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO; | |
| 17 | 17 | import org.springframework.stereotype.Service; |
| 18 | 18 | import org.springframework.transaction.annotation.Transactional; |
| 19 | 19 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImplTest.java
| ... | ... | @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2Cl |
| 7 | 7 | import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientPageReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; |
| 10 | -import cn.iocoder.yudao.module.system.dal.mysql.auth.OAuth2ClientMapper; | |
| 10 | +import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper; | |
| 11 | 11 | import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer; |
| 12 | 12 | import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientServiceImpl; |
| 13 | 13 | import org.junit.jupiter.api.Disabled; | ... | ... |