diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java index d82731aab..536aecfd4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/OAuth2Controller.java @@ -1,11 +1,22 @@ package cn.iocoder.yudao.module.system.controller.admin.auth; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; + @Api(tags = "管理后台 - OAuth2.0 授权") @RestController @RequestMapping("/system/oauth2") @@ -21,4 +32,37 @@ public class OAuth2Controller { // GET oauth/authorize AuthorizationEndpoint + @PostMapping("/authorize") + @ApiOperation(value = "申请授权", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被调用") + @ApiImplicitParams({ + @ApiImplicitParam(name = "response_type", required = true, value = "响应类型", example = "code", dataTypeClass = String.class), + @ApiImplicitParam(name = "client_id", required = true, value = "客户端编号", example = "tudou", dataTypeClass = String.class), + @ApiImplicitParam(name = "scope", value = "授权范围", example = "userinfo.read", dataTypeClass = String.class), // 多个使用逗号分隔 + @ApiImplicitParam(name = "redirect_uri", required = true, value = "重定向 URI", example = "https://www.iocoder.cn", dataTypeClass = String.class), + @ApiImplicitParam(name = "state", example = "123321", dataTypeClass = String.class) + }) + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 + // 因为前后端分离,Axios 无法很好的处理 302 重定向,所以和 Spring Security OAuth 略有不同,返回结果是重定向的 URL,剩余交给前端处理 + public CommonResult authorize(@RequestParam("response_type") String responseType, + @RequestParam("client_id") String clientId, + @RequestParam(value = "scope", required = false) String scope, + @RequestParam("redirect_uri") String redirectUri, + @RequestParam(value = "state", required = false) String state) { + // 0. 校验用户已经登录。通过 Spring Security 实现 + + // 1.1 校验 responseType 是否满足 code 或者 token 值 + if (!StrUtil.equalsAny(responseType, "code", "token")) { + throw exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "response_type 参数值允许 code 和 token"); + } + // 1.2 校验 redirectUri 重定向域名是否合法 + + // 1.3 校验 scope 是否在 Client 授权范围内 + + // 2.1 如果是 code 授权码模式,则发放 code 授权码,并重定向 + + // 2.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向 + // TODO 需要确认,是否要 refreshToken 生成 + return CommonResult.success(""); + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java index 2cd2b7466..4c13263e5 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/client/OAuth2ClientBaseVO.java @@ -55,10 +55,6 @@ public class OAuth2ClientBaseVO { private List<@NotEmpty(message = "重定向的 URI 不能为空") @URL(message = "重定向的 URI 格式不正确") String> redirectUris; - @ApiModelProperty(value = "是否自动授权", required = true, example = "true") - @NotNull(message = "是否自动授权不能为空") - private Boolean autoApprove; - @ApiModelProperty(value = "授权类型", required = true, example = "password", notes = "参见 OAuth2GrantTypeEnum 枚举") @NotNull(message = "授权类型不能为空") private List authorizedGrantTypes; @@ -66,6 +62,9 @@ public class OAuth2ClientBaseVO { @ApiModelProperty(value = "授权范围", example = "user_info") private List scopes; + @ApiModelProperty(value = "自动通过的授权范围", example = "user_info") + private List autoApproveScopes; + @ApiModelProperty(value = "权限", example = "system:user:query") private List authorities; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/OAuth2ClientDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/OAuth2ClientDO.java index 9b6e36b6e..dee649e5e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/OAuth2ClientDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/OAuth2ClientDO.java @@ -70,10 +70,6 @@ public class OAuth2ClientDO extends BaseDO { */ @TableField(typeHandler = JacksonTypeHandler.class) private List redirectUris; - /** - * 是否自动授权 - */ - private Boolean autoApprove; /** * 授权类型(模式) * @@ -86,6 +82,13 @@ public class OAuth2ClientDO extends BaseDO { */ @TableField(typeHandler = JacksonTypeHandler.class) private List scopes; + /** + * 自动授权的 Scope + * + * code 授权时,如果 scope 在这个范围内,则自动通过 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List autoApproveScopes; /** * 权限 */ diff --git a/yudao-ui-admin/src/api/login.js b/yudao-ui-admin/src/api/login.js index eb643e3a6..75846db52 100644 --- a/yudao-ui-admin/src/api/login.js +++ b/yudao-ui-admin/src/api/login.js @@ -109,3 +109,20 @@ export function refreshToken() { method: 'post' }) } + +// ========== OAUTH 2.0 相关 ========== +export function authorize() { + return service({ + url: '/system/oauth2/authorize', + headers:{ + 'Content-type': 'application/x-www-form-urlencoded', + "Access-Control-Allow-Origin": "*" + }, + params: { + response_type: 'code', + client_id: 'test', + redirect_uri: 'https://www.iocoder.cn', + }, + method: 'post' + }) +} diff --git a/yudao-ui-admin/src/router/index.js b/yudao-ui-admin/src/router/index.js index cc9b374cb..e6b3d6e01 100644 --- a/yudao-ui-admin/src/router/index.js +++ b/yudao-ui-admin/src/router/index.js @@ -42,6 +42,11 @@ export const constantRoutes = [ component: (resolve) => require(['@/views/login'], resolve), hidden: true }, + { + path: '/authorize', + component: (resolve) => require(['@/views/authorize'], resolve), + hidden: true + }, { path: '/social-login', component: (resolve) => require(['@/views/socialLogin'], resolve), diff --git a/yudao-ui-admin/src/views/authorize.vue b/yudao-ui-admin/src/views/authorize.vue new file mode 100644 index 000000000..37bba7aa2 --- /dev/null +++ b/yudao-ui-admin/src/views/authorize.vue @@ -0,0 +1,169 @@ + + + + diff --git a/yudao-ui-admin/src/views/system/oauth2/client/index.vue b/yudao-ui-admin/src/views/system/oauth2/client/index.vue index 37f16635f..72bbef1fe 100755 --- a/yudao-ui-admin/src/views/system/oauth2/client/index.vue +++ b/yudao-ui-admin/src/views/system/oauth2/client/index.vue @@ -108,23 +108,16 @@ - - - 自动登录 - 手动登录 - - - - - - - + + + + + @@ -196,7 +189,6 @@ export default { accessTokenValiditySeconds: [{ required: true, message: "访问令牌的有效期不能为空", trigger: "blur" }], refreshTokenValiditySeconds: [{ required: true, message: "刷新令牌的有效期不能为空", trigger: "blur" }], redirectUris: [{ required: true, message: "可重定向的 URI 地址不能为空", trigger: "blur" }], - autoApprove: [{ required: true, message: "是否自动授权不能为空", trigger: "blur" }], authorizedGrantTypes: [{ required: true, message: "授权类型不能为空", trigger: "blur" }], } }; @@ -235,9 +227,9 @@ export default { accessTokenValiditySeconds: 30 * 60, refreshTokenValiditySeconds: 30 * 24 * 60, redirectUris: [], - autoApprove: true, authorizedGrantTypes: [], scopes: [], + autoApproveScopes: [], authorities: [], resourceIds: [], additionalInformation: undefined,