From 9054a772b031244a9c2a79c492f355b7e00b125d Mon Sep 17 00:00:00 2001 From: xingyu Date: Tue, 20 Sep 2022 18:00:43 +0800 Subject: [PATCH 01/38] =?UTF-8?q?feat:=20=E5=8D=87=E7=BA=A7=E4=BE=9D?= =?UTF-8?q?=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 +- yudao-dependencies/pom.xml | 22 +++--- .../yudao-spring-boot-starter-biz-pay/pom.xml | 4 +- .../pom.xml | 4 +- .../convert/message/BpmMessageConvert.java | 5 ++ .../app/banner/AppBannerController.java | 5 +- .../dto/send/SmsSendSingleToUserReqDTO.java | 1 - yudao-ui-admin-vue3/package.json | 70 +++++++++---------- 8 files changed, 59 insertions(+), 56 deletions(-) diff --git a/pom.xml b/pom.xml index 63aa70ecb..4fe52775b 100644 --- a/pom.xml +++ b/pom.xml @@ -35,8 +35,8 @@ 3.0.0-M5 3.8.0 - 1.18.20 - 1.4.1.Final + 1.18.24 + 1.5.2.Final UTF-8 diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index d7912ba69..99998b5eb 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -22,11 +22,11 @@ 1.6.6 2.5 - 1.2.11 + 1.2.12 3.5.2 3.5.2 - 3.5.0 - 3.17.4 + 3.5.2 + 3.17.6 1.9.2 @@ -37,21 +37,21 @@ 2.6.7 0.31.0 - 7.2.6.RELEASE - 0.1.16 + 7.2.9.RELEASE + 1.0.3 4.0.0 6.7.2 3.0.4 - 1.18.20 - 1.4.1.Final - 5.8.5 + 1.18.24 + 1.5.2.Final + 5.8.6 3.1.1 2.3 1.0.5 - 1.2.83 - 30.1.1-jre + 1.2.83 + 31.1-jre 5.1.0 2.12.2 3.8.0 @@ -60,7 +60,7 @@ 1.3.0 8.2.2 - 4.6.0 + 4.6.1 2.2.1 3.1.561 1.2.7 diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml b/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml index e6106b9d9..4a6f92dca 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml @@ -52,7 +52,7 @@ com.alipay.sdk alipay-sdk-java - 4.31.72.ALL + 4.33.39.ALL org.bouncycastle @@ -63,7 +63,7 @@ com.github.binarywang weixin-java-pay - 4.3.8.B + 4.4.0 diff --git a/yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml b/yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml index 2dc2fe688..8af0041a9 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml @@ -35,12 +35,12 @@ com.github.binarywang wx-java-mp-spring-boot-starter - 4.3.8.B + 4.4.0 com.github.binarywang wx-java-miniapp-spring-boot-starter - 4.3.8.B + 4.4.0 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java index 92683f4c9..99b7bebf2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.convert.message; import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; import java.util.Map; @@ -11,6 +12,10 @@ public interface BpmMessageConvert { BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class); + @Mapping(target = "mobile", ignore = true) + @Mapping(source = "userId", target = "userId") + @Mapping(source = "templateCode", target = "templateCode") + @Mapping(source = "templateParams", target = "templateParams") SmsSendSingleToUserReqDTO convert(Long userId, String templateCode, Map templateParams); } diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/app/banner/AppBannerController.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/app/banner/AppBannerController.java index 3d9d58eb8..9af420a61 100644 --- a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/app/banner/AppBannerController.java +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/controller/app/banner/AppBannerController.java @@ -7,13 +7,13 @@ import cn.iocoder.yudao.module.market.dal.dataobject.banner.BannerDO; import cn.iocoder.yudao.module.market.service.banner.BannerService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -27,8 +27,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Validated public class AppBannerController { - // TODO @xia:使用 @Resource 哈 - @Autowired + @Resource private BannerService bannerService; // TODO @xia:新建一个 AppBannerRespVO,只返回必要的字段。status 要过滤下。然后 sort 下结果 diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java index 67a5d93d2..ef77780de 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.validation.Mobile; import lombok.Data; import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; import java.util.Map; /** diff --git a/yudao-ui-admin-vue3/package.json b/yudao-ui-admin-vue3/package.json index 81c41cc42..0a3de9a1c 100644 --- a/yudao-ui-admin-vue3/package.json +++ b/yudao-ui-admin-vue3/package.json @@ -1,6 +1,6 @@ { "name": "ruoyi-vue-pro-vue3", - "version": "1.6.3.1611", + "version": "1.6.4.1611", "description": "基于vue3、element-plus、typesScript、vite3", "author": "xingyu", "private": false, @@ -25,57 +25,57 @@ "p": "plop" }, "dependencies": { - "@iconify/iconify": "^2.2.1", - "@vueuse/core": "^9.1.0", - "@wangeditor/editor": "^5.1.14", + "@iconify/iconify": "^3.0.0", + "@vueuse/core": "^9.2.0", + "@wangeditor/editor": "^5.1.18", "@wangeditor/editor-for-vue": "^5.1.10", - "@zxcvbn-ts/core": "^2.0.4", + "@zxcvbn-ts/core": "^2.0.5", "animate.css": "^4.1.1", "axios": "^0.27.2", "crypto-js": "^4.1.1", - "dayjs": "^1.11.4", + "dayjs": "^1.11.5", "echarts": "^5.3.3", "echarts-wordcloud": "^2.0.0", - "element-plus": "2.2.12", + "element-plus": "2.2.17", "intro.js": "^6.0.0", "jsencrypt": "^3.2.1", "lodash-es": "^4.17.21", "mitt": "^3.0.0", "nprogress": "^0.2.0", - "pinia": "^2.0.17", + "pinia": "^2.0.22", "pinia-plugin-persist": "^1.0.0", "qrcode": "^1.5.1", "qs": "^6.11.0", "url": "^0.11.0", - "vue": "3.2.37", + "vue": "3.2.39", "vue-cropper": "^1.0.3", "vue-i18n": "9.2.2", - "vue-router": "^4.1.3", + "vue-router": "^4.1.5", "vue-types": "^4.2.1", "web-storage-cache": "^1.1.1" }, "devDependencies": { - "@commitlint/cli": "^17.0.3", - "@commitlint/config-conventional": "^17.0.3", - "@iconify/json": "^2.1.89", - "@intlify/vite-plugin-vue-i18n": "^6.0.0", + "@commitlint/cli": "^17.1.2", + "@commitlint/config-conventional": "^17.1.0", + "@iconify/json": "^2.1.110", + "@intlify/vite-plugin-vue-i18n": "^6.0.1", "@purge-icons/generated": "^0.9.0", "@types/intro.js": "^5.1.0", "@types/lodash-es": "^4.17.6", - "@types/node": "^18.6.5", + "@types/node": "^18.7.18", "@types/nprogress": "^0.2.0", - "@types/qrcode": "^1.4.2", + "@types/qrcode": "^1.5.0", "@types/qs": "^6.9.7", - "@typescript-eslint/eslint-plugin": "^5.33.0", - "@typescript-eslint/parser": "^5.33.0", - "@vitejs/plugin-vue": "^3.0.1", - "@vitejs/plugin-vue-jsx": "^2.0.0", - "autoprefixer": "^10.4.8", - "eslint": "^8.21.0", + "@typescript-eslint/eslint-plugin": "^5.38.0", + "@typescript-eslint/parser": "^5.38.0", + "@vitejs/plugin-vue": "^3.1.0", + "@vitejs/plugin-vue-jsx": "^2.0.1", + "autoprefixer": "^10.4.11", + "eslint": "^8.23.1", "eslint-config-prettier": "^8.5.0", - "eslint-define-config": "^1.6.0", + "eslint-define-config": "^1.7.0", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-vue": "^9.3.0", + "eslint-plugin-vue": "^9.5.1", "less": "^4.1.3", "lint-staged": "^13.0.3", "plop": "^3.1.1", @@ -84,24 +84,24 @@ "postcss-less": "^6.0.0", "prettier": "^2.7.1", "rimraf": "^3.0.2", - "rollup": "^2.77.2", - "stylelint": "^14.9.1", + "rollup": "^2.79.0", + "stylelint": "^14.12.0", "stylelint-config-html": "^1.1.0", "stylelint-config-prettier": "^9.0.3", - "stylelint-config-recommended": "^8.0.0", - "stylelint-config-standard": "^26.0.0", + "stylelint-config-recommended": "^9.0.0", + "stylelint-config-standard": "^28.0.0", "stylelint-order": "^5.0.0", - "typescript": "4.7.4", - "unplugin-vue-define-options": "^0.7.3", - "vite": "3.0.5", + "typescript": "4.8.3", + "unplugin-vue-define-options": "^0.11.2", + "vite": "3.1.3", "vite-plugin-compression": "^0.5.1", - "vite-plugin-eslint": "^1.7.0", + "vite-plugin-eslint": "^1.8.1", "vite-plugin-html": "^3.2.0", - "vite-plugin-purge-icons": "^0.9.0", + "vite-plugin-purge-icons": "^0.9.1", "vite-plugin-style-import": "^2.0.0", "vite-plugin-svg-icons": "^2.0.1", - "vite-plugin-windicss": "^1.8.7", - "vue-tsc": "^0.39.5", + "vite-plugin-windicss": "^1.8.8", + "vue-tsc": "^0.40.13", "windicss": "^3.5.6" }, "engines": { From 65c86878e912bb32e37fe7cfe5de8aee0caa247c Mon Sep 17 00:00:00 2001 From: xingyu Date: Wed, 21 Sep 2022 16:17:53 +0800 Subject: [PATCH 02/38] =?UTF-8?q?feat:=20=E5=8D=87=E7=BA=A7=E4=BE=9D?= =?UTF-8?q?=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-ui-admin-vue3/package.json | 2 +- .../src/components/Dialog/src/Dialog.vue | 2 +- .../src/components/Editor/src/Editor.vue | 2 +- .../infra/codegen/components/GenInfoForm.vue | 46 +++++++++++++++++-- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/yudao-ui-admin-vue3/package.json b/yudao-ui-admin-vue3/package.json index 0a3de9a1c..e35ea5779 100644 --- a/yudao-ui-admin-vue3/package.json +++ b/yudao-ui-admin-vue3/package.json @@ -1,6 +1,6 @@ { "name": "ruoyi-vue-pro-vue3", - "version": "1.6.4.1611", + "version": "1.6.4.1641", "description": "基于vue3、element-plus、typesScript、vite3", "author": "xingyu", "private": false, diff --git a/yudao-ui-admin-vue3/src/components/Dialog/src/Dialog.vue b/yudao-ui-admin-vue3/src/components/Dialog/src/Dialog.vue index c23d04fcf..a30c728ea 100644 --- a/yudao-ui-admin-vue3/src/components/Dialog/src/Dialog.vue +++ b/yudao-ui-admin-vue3/src/components/Dialog/src/Dialog.vue @@ -74,7 +74,7 @@ const dialogStyle = computed(() => { + + + + + + + +
+ 您未登录,点击 跳转 SSO 单点登录 +
+ + + + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantPackageDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantPackageDO.java index 430c3a080..dba7569af 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantPackageDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/tenant/TenantPackageDO.java @@ -34,7 +34,7 @@ public class TenantPackageDO extends BaseDO { */ private String name; /** - * 租户状态 + * 租户套餐状态 * * 枚举 {@link CommonStatusEnum} */ From 0df44b51e43c5d1501d8e64b3a28a77d26243a1d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 29 Sep 2022 23:59:42 +0800 Subject: [PATCH 06/38] =?UTF-8?q?=E5=AE=8C=E6=88=90=20yudao-sso-demo-by-co?= =?UTF-8?q?de=20=E4=BD=BF=E7=94=A8=20code=20=E6=8E=88=E6=9D=83=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E8=8E=B7=E5=BE=97=E8=AE=BF=E9=97=AE=E4=BB=A4=E7=89=8C?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-example/yudao-sso-demo-by-code/pom.xml | 6 ++ .../yudao/ssodemo/client/OAuth2Client.java | 75 +++++++++++++++++++ .../ssodemo/client/dto/CommonResult.java | 28 +++++++ .../client/dto/OAuth2AccessTokenRespDTO.java | 45 +++++++++++ .../ssodemo/controller/AuthController.java | 27 ++++++- .../framework/SecurityConfiguration.java | 5 +- .../src/main/resources/static/callback.html | 61 +++++++++++++++ .../static/{login.html => index.html} | 4 +- 8 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/CommonResult.java create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/OAuth2AccessTokenRespDTO.java create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/resources/static/callback.html rename yudao-example/yudao-sso-demo-by-code/src/main/resources/static/{login.html => index.html} (80%) diff --git a/yudao-example/yudao-sso-demo-by-code/pom.xml b/yudao-example/yudao-sso-demo-by-code/pom.xml index 0227d37c3..3ea138ac4 100644 --- a/yudao-example/yudao-sso-demo-by-code/pom.xml +++ b/yudao-example/yudao-sso-demo-by-code/pom.xml @@ -48,6 +48,12 @@ org.springframework.boot spring-boot-starter-security
+ + + org.projectlombok + lombok + true + diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java new file mode 100644 index 000000000..351224bf0 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.ssodemo.client; + +import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; +import cn.iocoder.yudao.ssodemo.client.dto.OAuth2AccessTokenRespDTO; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.util.Base64Utils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.nio.charset.StandardCharsets; + +/** + * OAuth 2.0 客户端 + */ +@Component +public class OAuth2Client { + + private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2/"; + + /** + * 租户编号 + * + * 默认使用 1;如果使用别的租户,可以调整 + */ + private static final Long TENANT_ID = 1L; + + private static final String CLIENT_ID = "yudao-sso-demo-by-code"; + private static final String CLIENT_SECRET = "test"; + + +// @Resource // 可优化,注册一个 RestTemplate Bean,然后注入 + private final RestTemplate restTemplate = new RestTemplate(); + + /** + * 使用 code 授权码,获得访问令牌 + * + * @param code 授权码 + * @param redirectUri 重定向 URI + * @return 访问令牌 + */ + public CommonResult postAccessToken(String code, String redirectUri) { + // 1.1 构建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + headers.set("tenant-id", TENANT_ID.toString()); + addClientHeader(headers); + // 1.2 构建请求参数 + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("grant_type", "authorization_code"); + body.add("code", code); + body.add("redirect_uri", redirectUri); +// body.add("state", ""); // 选填;填了会校验 + + // 2. 执行请求 + ResponseEntity> exchange = restTemplate.exchange( + BASE_URL + "/token", + HttpMethod.POST, + new HttpEntity<>(body, headers), + new ParameterizedTypeReference>() {}); // 解决 CommonResult 的泛型丢失 + Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功"); + return exchange.getBody(); + } + + private static void addClientHeader(HttpHeaders headers) { + // client 拼接,需要 BASE64 编码 + String client = CLIENT_ID + ":" + CLIENT_SECRET; + client = Base64Utils.encodeToString(client.getBytes(StandardCharsets.UTF_8)); + headers.add("Authorization", "Basic " + client); + } + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/CommonResult.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/CommonResult.java new file mode 100644 index 000000000..548fe51e4 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/CommonResult.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.ssodemo.client.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 通用返回 + * + * @param 数据泛型 + */ +@Data +public class CommonResult implements Serializable { + + /** + * 错误码 + */ + private Integer code; + /** + * 返回数据 + */ + private T data; + /** + * 错误提示,用户可阅读 + */ + private String msg; + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/OAuth2AccessTokenRespDTO.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/OAuth2AccessTokenRespDTO.java new file mode 100644 index 000000000..14c01b843 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/OAuth2AccessTokenRespDTO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.ssodemo.client.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 访问令牌 Response DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2AccessTokenRespDTO { + + /** + * 访问令牌 + */ + @JsonProperty("access_token") + private String accessToken; + + /** + * 刷新令牌 + */ + @JsonProperty("refresh_token") + private String refreshToken; + + /** + * 令牌类型 + */ + @JsonProperty("token_type") + private String tokenType; + + /** + * 过期时间;单位:秒 + */ + @JsonProperty("expires_in") + private Long expiresIn; + + /** + * 授权范围;如果多个授权范围,使用空格分隔 + */ + private String scope; + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java index 8445ff288..8ed601ba5 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java @@ -1,14 +1,33 @@ package cn.iocoder.yudao.ssodemo.controller; -import org.springframework.stereotype.Controller; +import cn.iocoder.yudao.ssodemo.client.OAuth2Client; +import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; +import cn.iocoder.yudao.ssodemo.client.dto.OAuth2AccessTokenRespDTO; 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; -@Controller("/auth") +import javax.annotation.Resource; + +@RestController +@RequestMapping("/auth") public class AuthController { - @PostMapping("/login-by-code") - public void loginByCode() { + @Resource + private OAuth2Client oauth2Client; + /** + * 使用 code 访问令牌,获得访问令牌 + * + * @param code 授权码 + * @param redirectUri 重定向 URI + * @return 访问令牌;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段 + */ + @PostMapping("/login-by-code") + public CommonResult loginByCode(@RequestParam("code") String code, + @RequestParam("redirectUri") String redirectUri) { + return oauth2Client.postAccessToken(code, redirectUri); } } diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/SecurityConfiguration.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/SecurityConfiguration.java index 9e925913a..608191350 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/SecurityConfiguration.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/SecurityConfiguration.java @@ -10,9 +10,12 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { - httpSecurity.authorizeRequests() + httpSecurity.csrf().disable() // 禁用 CSRF 保护 + .authorizeRequests() // 1. 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() + // 2. 登录相关的接口,可匿名访问 + .antMatchers("/auth/login-by-code").permitAll() // last. 兜底规则,必须认证 .and().authorizeRequests() .anyRequest().authenticated(); diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/callback.html b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/callback.html new file mode 100644 index 000000000..60199e29e --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/callback.html @@ -0,0 +1,61 @@ + + + + + SSO 授权后的回调页 + + + + + + + + +正在使用 code 授权码,进行 accessToken 访问令牌的获取 + + diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/login.html b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html similarity index 80% rename from yudao-example/yudao-sso-demo-by-code/src/main/resources/static/login.html rename to yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html index b468d84f1..2163a466c 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/login.html +++ b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html @@ -5,8 +5,6 @@ 首页 - - - -
- 您未登录,点击 跳转 SSO 单点登录 -
+ + - + + + From fc7a6c782a18074d41d80377e4ac993d65c35fe6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Oct 2022 10:52:27 +0800 Subject: [PATCH 08/38] =?UTF-8?q?=E5=AE=8C=E6=88=90=20yudao-sso-demo-by-co?= =?UTF-8?q?de=20=E5=AE=9E=E7=8E=B0=E8=8E=B7=E5=BE=97=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/ssodemo/client/OAuth2Client.java | 4 +- .../yudao/ssodemo/client/UserClient.java | 50 +++++++++ .../client/dto/user/UserInfoRespDTO.java | 97 +++++++++++++++++ .../ssodemo/controller/UserController.java | 14 ++- .../ssodemo/framework/core/LoginUser.java | 5 + .../ssodemo/framework/core/SecurityUtils.java | 102 ++++++++++++++++++ .../core/TokenAuthenticationFilter.java | 51 +-------- .../src/main/resources/static/index.html | 6 +- 8 files changed, 274 insertions(+), 55 deletions(-) create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/UserClient.java create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/user/UserInfoRespDTO.java create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/SecurityUtils.java diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java index 8449dd39b..f29da71a4 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java @@ -20,14 +20,14 @@ import java.nio.charset.StandardCharsets; @Component public class OAuth2Client { - private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2/"; + private static final String BASE_URL = "http://127.0.0.1:48080/admin-api/system/oauth2"; /** * 租户编号 * * 默认使用 1;如果使用别的租户,可以调整 */ - private static final Long TENANT_ID = 1L; + public static final Long TENANT_ID = 1L; private static final String CLIENT_ID = "yudao-sso-demo-by-code"; private static final String CLIENT_SECRET = "test"; diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/UserClient.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/UserClient.java new file mode 100644 index 000000000..8b2fa2a2e --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/UserClient.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.ssodemo.client; + +import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; +import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO; +import cn.iocoder.yudao.ssodemo.framework.core.LoginUser; +import cn.iocoder.yudao.ssodemo.framework.core.SecurityUtils; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +/** + * OAuth 2.0 客户端 + */ +@Component +public class UserClient { + + private static final String BASE_URL = "http://127.0.0.1:48080/admin-api//system/oauth2/user"; + + // @Resource // 可优化,注册一个 RestTemplate Bean,然后注入 + private final RestTemplate restTemplate = new RestTemplate(); + + public CommonResult getUser() { + // 1.1 构建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + headers.set("tenant-id", OAuth2Client.TENANT_ID.toString()); + addTokenHeader(headers); + // 1.2 构建请求参数 + MultiValueMap body = new LinkedMultiValueMap<>(); + + // 2. 执行请求 + ResponseEntity> exchange = restTemplate.exchange( + BASE_URL + "/get", + HttpMethod.GET, + new HttpEntity<>(body, headers), + new ParameterizedTypeReference>() {}); // 解决 CommonResult 的泛型丢失 + Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功"); + return exchange.getBody(); + } + + private static void addTokenHeader(HttpHeaders headers) { + LoginUser loginUser = SecurityUtils.getLoginUser(); + Assert.notNull(loginUser, "登录用户不能为空"); + headers.add("Authorization", "Bearer " + loginUser.getAccessToken()); + } +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/user/UserInfoRespDTO.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/user/UserInfoRespDTO.java new file mode 100644 index 000000000..e81bea9eb --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/user/UserInfoRespDTO.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.ssodemo.client.dto.user; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 获得用户基本信息 Response dto + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserInfoRespDTO { + + /** + * 用户编号 + */ + private Long id; + + /** + * 用户账号 + */ + private String username; + + /** + * 用户昵称 + */ + private String nickname; + + /** + * 用户邮箱 + */ + private String email; + /** + * 手机号码 + */ + private String mobile; + + /** + * 用户性别 + */ + private Integer sex; + + /** + * 用户头像 + */ + private String avatar; + + /** + * 所在部门 + */ + private Dept dept; + + /** + * 所属岗位数组 + */ + private List posts; + + /** + * 部门 + */ + @Data + public static class Dept { + + /** + * 部门编号 + */ + private Long id; + + /** + * 部门名称 + */ + private String name; + + } + + /** + * 岗位 + */ + @Data + public static class Post { + + /** + * 岗位编号 + */ + private Long id; + + /** + * 岗位名称 + */ + private String name; + + } + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/UserController.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/UserController.java index 77e4a9113..5626b7140 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/UserController.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/UserController.java @@ -1,21 +1,29 @@ package cn.iocoder.yudao.ssodemo.controller; +import cn.iocoder.yudao.ssodemo.client.UserClient; +import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; +import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; + @RestController @RequestMapping("/user") public class UserController { + @Resource + private UserClient userClient; + /** * 获得当前登录用户的基本信息 * - * @return TODO + * @return 用户信息;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段 */ @GetMapping("/get") - public String getUser() { - return ""; + public CommonResult getUser() { + return userClient.getUser(); } } diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/LoginUser.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/LoginUser.java index e785e1544..44f3edf54 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/LoginUser.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/LoginUser.java @@ -29,4 +29,9 @@ public class LoginUser { */ private List scopes; + /** + * 访问令牌 + */ + private String accessToken; + } diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/SecurityUtils.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/SecurityUtils.java new file mode 100644 index 000000000..adfd32b60 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/SecurityUtils.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.ssodemo.framework.core; + +import org.springframework.lang.Nullable; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.util.Collections; + +/** + * 安全服务工具类 + * + * @author 芋道源码 + */ +public class SecurityUtils { + + public static final String AUTHORIZATION_BEARER = "Bearer"; + + private SecurityUtils() {} + + /** + * 从请求中,获得认证 Token + * + * @param request 请求 + * @param header 认证 Token 对应的 Header 名字 + * @return 认证 Token + */ + public static String obtainAuthorization(HttpServletRequest request, String header) { + String authorization = request.getHeader(header); + if (!StringUtils.hasText(authorization)) { + return null; + } + int index = authorization.indexOf(AUTHORIZATION_BEARER + " "); + if (index == -1) { // 未找到 + return null; + } + return authorization.substring(index + 7).trim(); + } + + /** + * 获得当前认证信息 + * + * @return 认证信息 + */ + public static Authentication getAuthentication() { + SecurityContext context = SecurityContextHolder.getContext(); + if (context == null) { + return null; + } + return context.getAuthentication(); + } + + /** + * 获取当前用户 + * + * @return 当前用户 + */ + @Nullable + public static LoginUser getLoginUser() { + Authentication authentication = getAuthentication(); + if (authentication == null) { + return null; + } + return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null; + } + + /** + * 获得当前用户的编号,从上下文中 + * + * @return 用户编号 + */ + @Nullable + public static Long getLoginUserId() { + LoginUser loginUser = getLoginUser(); + return loginUser != null ? loginUser.getId() : null; + } + + /** + * 设置当前用户 + * + * @param loginUser 登录用户 + * @param request 请求 + */ + public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) { + // 创建 Authentication,并设置到上下文 + Authentication authentication = buildAuthentication(loginUser, request); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) { + // 创建 UsernamePasswordAuthenticationToken 对象 + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( + loginUser, null, Collections.emptyList()); + authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + return authenticationToken; + } + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/TokenAuthenticationFilter.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/TokenAuthenticationFilter.java index a895fc2c5..cb90b4840 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/TokenAuthenticationFilter.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/TokenAuthenticationFilter.java @@ -3,10 +3,6 @@ package cn.iocoder.yudao.ssodemo.framework.core; import cn.iocoder.yudao.ssodemo.client.OAuth2Client; import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2CheckTokenRespDTO; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; @@ -17,7 +13,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Collections; /** * Token 过滤器,验证 token 的有效性 @@ -35,13 +30,13 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 1. 获得访问令牌 - String token = obtainAuthorization(request); + String token = SecurityUtils.obtainAuthorization(request, "Authentication"); if (StringUtils.hasText(token)) { // 2. 基于 token 构建登录用户 LoginUser loginUser = buildLoginUserByToken(token); // 3. 设置当前用户 if (loginUser != null) { - setLoginUser(loginUser, request); + SecurityUtils.setLoginUser(loginUser, request); } } @@ -58,50 +53,12 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { } // 构建登录用户 return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType()) - .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes()); + .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes()) + .setAccessToken(accessToken.getAccessToken()); } catch (Exception exception) { // 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可 return null; } } - /** - * 从请求 Header 中,获得访问令牌 - * - * @param request 请求 - * @return 访问令牌 - */ - private static String obtainAuthorization(HttpServletRequest request) { - String authorization = request.getHeader("Authentication"); - if (!StringUtils.hasText(authorization)) { - return null; - } - int index = authorization.indexOf("Bearer "); - if (index == -1) { // 未找到 - return null; - } - return authorization.substring(index + 7).trim(); - } - - /** - * 设置当前用户 - * - * @param loginUser 登录用户 - * @param request 请求 - */ - private static void setLoginUser(LoginUser loginUser, HttpServletRequest request) { - // 创建 Authentication,并设置到上下文 - Authentication authentication = buildAuthentication(loginUser, request); - SecurityContextHolder.getContext().setAuthentication(authentication); - } - - private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) { - // 创建 UsernamePasswordAuthenticationToken 对象 - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( - loginUser, null, Collections.emptyList()); - authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - return authenticationToken; - } - - } diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html index df037f4c5..491982bf9 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html +++ b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html @@ -43,7 +43,7 @@ alert('获得个人信息失败,原因:' + result.msg) return; } - $('nicknameSpan').html(result.data.nickname); + $('#nicknameSpan').html(result.data.nickname); } }); }) @@ -57,8 +57,8 @@ From ea71002ed6e77fb0e58baa3ba5e9dc7ebd889585 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Oct 2022 20:30:15 +0800 Subject: [PATCH 09/38] =?UTF-8?q?=E5=AE=8C=E6=88=90=20yudao-sso-demo-by-co?= =?UTF-8?q?de=20=E5=AE=9E=E7=8E=B0=E4=BF=AE=E6=94=B9=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=9A=84=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-example/yudao-sso-demo-by-code/pom.xml | 6 +++ .../yudao/ssodemo/client/OAuth2Client.java | 2 + .../yudao/ssodemo/client/UserClient.java | 27 +++++++++++- .../client/dto/user/UserUpdateReqDTO.java | 35 +++++++++++++++ .../ssodemo/controller/UserController.java | 17 +++++-- .../config/SecurityConfiguration.java | 22 ++++++---- .../TokenAuthenticationFilter.java | 4 +- .../core/handler/AccessDeniedHandlerImpl.java | 44 +++++++++++++++++++ .../handler/AuthenticationEntryPointImpl.java | 36 +++++++++++++++ .../core/{ => util}/SecurityUtils.java | 3 +- .../framework/core/util/ServletUtils.java | 28 ++++++++++++ .../src/main/resources/static/index.html | 29 +++++++++++- 12 files changed, 236 insertions(+), 17 deletions(-) create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/user/UserUpdateReqDTO.java rename yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/{ => filter}/TokenAuthenticationFilter.java (93%) create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/handler/AccessDeniedHandlerImpl.java create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/handler/AuthenticationEntryPointImpl.java rename yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/{ => util}/SecurityUtils.java (96%) create mode 100644 yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/util/ServletUtils.java diff --git a/yudao-example/yudao-sso-demo-by-code/pom.xml b/yudao-example/yudao-sso-demo-by-code/pom.xml index 3ea138ac4..9b003c4fb 100644 --- a/yudao-example/yudao-sso-demo-by-code/pom.xml +++ b/yudao-example/yudao-sso-demo-by-code/pom.xml @@ -49,6 +49,12 @@ spring-boot-starter-security + + cn.hutool + hutool-all + 5.8.5 + + org.projectlombok lombok diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java index f29da71a4..bdb417c41 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java @@ -16,6 +16,8 @@ import java.nio.charset.StandardCharsets; /** * OAuth 2.0 客户端 + * + * 对应调用 OAuth2OpenController 接口 */ @Component public class OAuth2Client { diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/UserClient.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/UserClient.java index 8b2fa2a2e..666bd3ee4 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/UserClient.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/UserClient.java @@ -2,8 +2,9 @@ package cn.iocoder.yudao.ssodemo.client; import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO; +import cn.iocoder.yudao.ssodemo.client.dto.user.UserUpdateReqDTO; import cn.iocoder.yudao.ssodemo.framework.core.LoginUser; -import cn.iocoder.yudao.ssodemo.framework.core.SecurityUtils; +import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.*; import org.springframework.stereotype.Component; @@ -13,7 +14,9 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; /** - * OAuth 2.0 客户端 + * 用户 User 信息的客户端 + * + * 对应调用 OAuth2UserController 接口 */ @Component public class UserClient { @@ -42,6 +45,26 @@ public class UserClient { return exchange.getBody(); } + public CommonResult updateUser(UserUpdateReqDTO updateReqDTO) { + // 1.1 构建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("tenant-id", OAuth2Client.TENANT_ID.toString()); + addTokenHeader(headers); + // 1.2 构建请求参数 + // 使用 updateReqDTO 即可 + + // 2. 执行请求 + ResponseEntity> exchange = restTemplate.exchange( + BASE_URL + "/update", + HttpMethod.PUT, + new HttpEntity<>(updateReqDTO, headers), + new ParameterizedTypeReference>() {}); // 解决 CommonResult 的泛型丢失 + Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功"); + return exchange.getBody(); + } + + private static void addTokenHeader(HttpHeaders headers) { LoginUser loginUser = SecurityUtils.getLoginUser(); Assert.notNull(loginUser, "登录用户不能为空"); diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/user/UserUpdateReqDTO.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/user/UserUpdateReqDTO.java new file mode 100644 index 000000000..e711d7311 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/dto/user/UserUpdateReqDTO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.ssodemo.client.dto.user; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 更新用户基本信息 Request DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserUpdateReqDTO { + + /** + * 用户昵称 + */ + private String nickname; + + /** + * 用户邮箱 + */ + private String email; + + /** + * 手机号码 + */ + private String mobile; + + /** + * 用户性别 + */ + private Integer sex; + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/UserController.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/UserController.java index 5626b7140..819c752bc 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/UserController.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/UserController.java @@ -3,9 +3,8 @@ package cn.iocoder.yudao.ssodemo.controller; import cn.iocoder.yudao.ssodemo.client.UserClient; import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; import cn.iocoder.yudao.ssodemo.client.dto.user.UserInfoRespDTO; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import cn.iocoder.yudao.ssodemo.client.dto.user.UserUpdateReqDTO; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -26,4 +25,16 @@ public class UserController { return userClient.getUser(); } + /** + * 更新当前登录用户的昵称 + * + * @param nickname 昵称 + * @return 成功 + */ + @PutMapping("/update") + public CommonResult updateUser(@RequestParam("nickname") String nickname) { + UserUpdateReqDTO updateReqDTO = new UserUpdateReqDTO(nickname, null, null, null); + return userClient.updateUser(updateReqDTO); + } + } diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/config/SecurityConfiguration.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/config/SecurityConfiguration.java index 3a27f0102..5c8a4e4b7 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/config/SecurityConfiguration.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/config/SecurityConfiguration.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.ssodemo.framework.config; -import cn.iocoder.yudao.ssodemo.framework.core.TokenAuthenticationFilter; +import cn.iocoder.yudao.ssodemo.framework.core.filter.TokenAuthenticationFilter; +import cn.iocoder.yudao.ssodemo.framework.core.handler.AccessDeniedHandlerImpl; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.annotation.Resource; @@ -12,17 +14,14 @@ import javax.annotation.Resource; @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { -// /** -// * Token 认证过滤器 Bean -// */ -// @Bean -// public TokenAuthenticationFilter authenticationTokenFilter(OAuth2Client oauth2Client) { -// return new TokenAuthenticationFilter(oauth2Client); -// } - @Resource private TokenAuthenticationFilter tokenAuthenticationFilter; + @Resource + private AccessDeniedHandlerImpl accessDeniedHandler; + @Resource + private AuthenticationEntryPoint authenticationEntryPoint; + @Override protected void configure(HttpSecurity httpSecurity) throws Exception { // 设置 URL 安全权限 @@ -36,7 +35,12 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { .and().authorizeRequests() .anyRequest().authenticated(); + // 设置处理器 + httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler) + .authenticationEntryPoint(authenticationEntryPoint); + // 添加 Token Filter httpSecurity.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } + } diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/TokenAuthenticationFilter.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/filter/TokenAuthenticationFilter.java similarity index 93% rename from yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/TokenAuthenticationFilter.java rename to yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/filter/TokenAuthenticationFilter.java index cb90b4840..106e1bd0d 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/TokenAuthenticationFilter.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/filter/TokenAuthenticationFilter.java @@ -1,8 +1,10 @@ -package cn.iocoder.yudao.ssodemo.framework.core; +package cn.iocoder.yudao.ssodemo.framework.core.filter; import cn.iocoder.yudao.ssodemo.client.OAuth2Client; import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2CheckTokenRespDTO; +import cn.iocoder.yudao.ssodemo.framework.core.LoginUser; +import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/handler/AccessDeniedHandlerImpl.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/handler/AccessDeniedHandlerImpl.java new file mode 100644 index 000000000..dccc35eb1 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/handler/AccessDeniedHandlerImpl.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.ssodemo.framework.core.handler; + +import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; +import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils; +import cn.iocoder.yudao.ssodemo.framework.core.util.ServletUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.access.ExceptionTranslationFilter; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 访问一个需要认证的 URL 资源,已经认证(登录)但是没有权限的情况下,返回 {@link GlobalErrorCodeConstants#FORBIDDEN} 错误码。 + * + * 补充:Spring Security 通过 {@link ExceptionTranslationFilter#handleAccessDeniedException(HttpServletRequest, HttpServletResponse, FilterChain, AccessDeniedException)} 方法,调用当前类 + * + * @author 芋道源码 + */ +@Component +@SuppressWarnings("JavadocReference") +@Slf4j +public class AccessDeniedHandlerImpl implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) + throws IOException, ServletException { + // 打印 warn 的原因是,不定期合并 warn,看看有没恶意破坏 + log.warn("[commence][访问 URL({}) 时,用户({}) 权限不够]", request.getRequestURI(), + SecurityUtils.getLoginUserId(), e); + // 返回 403 + CommonResult result = new CommonResult<>(); + result.setCode(HttpStatus.FORBIDDEN.value()); + result.setMsg("没有该操作权限"); + ServletUtils.writeJSON(response, result); + } + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/handler/AuthenticationEntryPointImpl.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/handler/AuthenticationEntryPointImpl.java new file mode 100644 index 000000000..241ff56f5 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/handler/AuthenticationEntryPointImpl.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.ssodemo.framework.core.handler; + +import cn.iocoder.yudao.ssodemo.client.dto.CommonResult; +import cn.iocoder.yudao.ssodemo.framework.core.util.ServletUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.access.ExceptionTranslationFilter; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 访问一个需要认证的 URL 资源,但是此时自己尚未认证(登录)的情况下,返回 {@link GlobalErrorCodeConstants#UNAUTHORIZED} 错误码,从而使前端重定向到登录页 + * + * 补充:Spring Security 通过 {@link ExceptionTranslationFilter#sendStartAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, AuthenticationException)} 方法,调用当前类 + */ +@Component +@Slf4j +@SuppressWarnings("JavadocReference") // 忽略文档引用报错 +public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) { + log.debug("[commence][访问 URL({}) 时,没有登录]", request.getRequestURI(), e); + // 返回 401 + CommonResult result = new CommonResult<>(); + result.setCode(HttpStatus.UNAUTHORIZED.value()); + result.setMsg("账号未登录"); + ServletUtils.writeJSON(response, result); + } + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/SecurityUtils.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/util/SecurityUtils.java similarity index 96% rename from yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/SecurityUtils.java rename to yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/util/SecurityUtils.java index adfd32b60..0352a4785 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/SecurityUtils.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/util/SecurityUtils.java @@ -1,5 +1,6 @@ -package cn.iocoder.yudao.ssodemo.framework.core; +package cn.iocoder.yudao.ssodemo.framework.core.util; +import cn.iocoder.yudao.ssodemo.framework.core.LoginUser; import org.springframework.lang.Nullable; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/util/ServletUtils.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/util/ServletUtils.java new file mode 100644 index 000000000..50f1836f7 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/core/util/ServletUtils.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.ssodemo.framework.core.util; + +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.json.JSONUtil; +import org.springframework.http.MediaType; + +import javax.servlet.http.HttpServletResponse; + +/** + * 客户端工具类 + * + * @author 芋道源码 + */ +public class ServletUtils { + + /** + * 返回 JSON 字符串 + * + * @param response 响应 + * @param object 对象,会序列化成 JSON 字符串 + */ + @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码 + public static void writeJSON(HttpServletResponse response, Object object) { + String content = JSONUtil.toJsonStr(object); + ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE); + } + +} diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html index 491982bf9..0f69e6b58 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html +++ b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html @@ -20,6 +20,33 @@ + '&response_type=' + responseType; } + /** + * 修改昵称 + */ + function updateNickname() { + const nickname = prompt("请输入新的昵称", ""); + if (!nickname) { + return; + } + // 更新用户的昵称 + const accessToken = localStorage.getItem('ACCESS-TOKEN'); + $.ajax({ + url: "http://127.0.0.1:18080/user/update?nickname=" + nickname, + method: 'PUT', + headers: { + 'Authentication': 'Bearer ' + accessToken + }, + success: function (result) { + if (result.code !== 0) { + alert('更新昵称失败,原因:' + result.msg) + return; + } + alert('更新昵称成功!'); + $('#nicknameSpan').html(nickname); + } + }); + } + $(function () { const accessToken = localStorage.getItem('ACCESS-TOKEN'); // 情况一:未登录 @@ -58,7 +85,7 @@ From ff54f169079ceb5b77d93cc60f5d2a167c6c253e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Oct 2022 20:49:11 +0800 Subject: [PATCH 10/38] =?UTF-8?q?=E5=AE=8C=E6=88=90=20yudao-sso-demo-by-co?= =?UTF-8?q?de=20=E5=88=B7=E6=96=B0=E8=AE=BF=E9=97=AE=E4=BB=A4=E7=89=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/ssodemo/client/OAuth2Client.java | 33 +++++++++++++++++++ .../ssodemo/controller/AuthController.java | 11 +++++++ .../src/main/resources/static/index.html | 29 +++++++++++++++- .../vo/open/OAuth2OpenCheckTokenRespVO.java | 1 + .../oauth2/vo/user/OAuth2UserInfoRespVO.java | 2 +- yudao-ui-admin/src/views/sso.vue | 2 +- 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java index bdb417c41..6e179c49c 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java @@ -68,6 +68,12 @@ public class OAuth2Client { return exchange.getBody(); } + /** + * 校验访问令牌,并返回它的基本信息 + * + * @param token 访问令牌 + * @return 访问令牌的基本信息 + */ public CommonResult checkToken(String token) { // 1.1 构建请求头 HttpHeaders headers = new HttpHeaders(); @@ -88,6 +94,33 @@ public class OAuth2Client { return exchange.getBody(); } + /** + * 使用刷新令牌,获得(刷新)访问令牌 + * + * @param refreshToken 刷新令牌 + * @return 访问令牌 + */ + public CommonResult refreshToken(String refreshToken) { + // 1.1 构建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + headers.set("tenant-id", TENANT_ID.toString()); + addClientHeader(headers); + // 1.2 构建请求参数 + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("grant_type", "refresh_token"); + body.add("refresh_token", refreshToken); + + // 2. 执行请求 + ResponseEntity> exchange = restTemplate.exchange( + BASE_URL + "/token", + HttpMethod.POST, + new HttpEntity<>(body, headers), + new ParameterizedTypeReference>() {}); // 解决 CommonResult 的泛型丢失 + Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功"); + return exchange.getBody(); + } + private static void addClientHeader(HttpHeaders headers) { // client 拼接,需要 BASE64 编码 String client = CLIENT_ID + ":" + CLIENT_SECRET; diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java index 21807170e..4dfa3d0b5 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java +++ b/yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java @@ -30,4 +30,15 @@ public class AuthController { return oauth2Client.postAccessToken(code, redirectUri); } + /** + * 使用刷新令牌,获得(刷新)访问令牌 + * + * @param refreshToken 刷新令牌 + * @return 访问令牌;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段 + */ + @PostMapping("/refresh-token") + public CommonResult refreshToken(@RequestParam("refreshToken") String refreshToken) { + return oauth2Client.refreshToken(refreshToken); + } + } diff --git a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html index 0f69e6b58..a4bfa666e 100644 --- a/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html +++ b/yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html @@ -47,6 +47,33 @@ }); } + /** + * 刷新令牌 + */ + function refreshToken() { + const refreshToken = localStorage.getItem('REFRESH-TOKEN'); + if (!refreshToken) { + alert("获取不到刷新令牌"); + return; + } + $.ajax({ + url: "http://127.0.0.1:18080/auth/refresh-token?refreshToken=" + refreshToken, + method: 'POST', + success: function (result) { + if (result.code !== 0) { + alert('刷新访问令牌失败,原因:' + result.msg) + return; + } + alert('更新访问令牌成功!'); + $('#accessTokenSpan').html(result.data.access_token); + + // 设置到 localStorage 中 + localStorage.setItem('ACCESS-TOKEN', result.data.access_token); + localStorage.setItem('REFRESH-TOKEN', result.data.refresh_token); + } + }); + } + $(function () { const accessToken = localStorage.getItem('ACCESS-TOKEN'); // 情况一:未登录 @@ -86,7 +113,7 @@ + diff --git a/yudao-example/yudao-sso-demo-by-password/src/main/resources/static/login.html b/yudao-example/yudao-sso-demo-by-password/src/main/resources/static/login.html new file mode 100644 index 000000000..4dd6a9105 --- /dev/null +++ b/yudao-example/yudao-sso-demo-by-password/src/main/resources/static/login.html @@ -0,0 +1,74 @@ + + + + + 登录 + + + + + + + 账号:
+ 密码:
+ + + + From bf700ab1fc79d23b882533981517217e70ef627e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 4 Oct 2022 23:11:27 +0800 Subject: [PATCH 16/38] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20yudao-sso-demo-by-pa?= =?UTF-8?q?ssword=20=E7=A4=BA=E4=BE=8B=EF=BC=8C=E5=9F=BA=E4=BA=8E=E5=AF=86?= =?UTF-8?q?=E7=A0=81=E6=A8=A1=E5=BC=8F=EF=BC=8C=E5=AE=9E=E7=8E=B0=20SSO=20?= =?UTF-8?q?=E5=8D=95=E7=82=B9=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/ssodemo/client/OAuth2Client.java | 2 +- .../src/main/resources/static/login.html | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/yudao-example/yudao-sso-demo-by-password/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java b/yudao-example/yudao-sso-demo-by-password/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java index b5f971989..4f6b63481 100644 --- a/yudao-example/yudao-sso-demo-by-password/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java +++ b/yudao-example/yudao-sso-demo-by-password/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java @@ -31,7 +31,7 @@ public class OAuth2Client { */ public static final Long TENANT_ID = 1L; - private static final String CLIENT_ID = "yudao-sso-demo-by-code"; + private static final String CLIENT_ID = "yudao-sso-demo-by-password"; private static final String CLIENT_SECRET = "test"; diff --git a/yudao-example/yudao-sso-demo-by-password/src/main/resources/static/login.html b/yudao-example/yudao-sso-demo-by-password/src/main/resources/static/login.html index 4dd6a9105..79b866bf2 100644 --- a/yudao-example/yudao-sso-demo-by-password/src/main/resources/static/login.html +++ b/yudao-example/yudao-sso-demo-by-password/src/main/resources/static/login.html @@ -13,31 +13,31 @@ */ function login() { const clientId = 'yudao-sso-demo-by-password'; // 可以改写成,你的 clientId - const clientSecret = 'test'; // 可以改写成,你的 clientSecret - const grantType = 'password'; // 密码模式 + const clientSecret = 'test'; // 可以改写成,你的 clientSecret + const grantType = 'password'; // 密码模式 - // 账号 + 密码 - const username = $('#username').val(); - const password = $('#password').val(); + // 账号 + 密码 + const username = $('#username').val(); + const password = $('#password').val(); if (username.length === 0 || password.length === 0) { alert('账号或密码未输入'); return; - } + } // 发起请求 $.ajax({ url: "http://127.0.0.1:48080/admin-api/system/oauth2/token?" // 客户端 - + "client_id=" + clientId + + "client_id=" + clientId + "&client_secret=" + clientSecret - // 密码模式的参数 - + "&grant_type=" + grantType - + "&username=" + username - + "&password=" + password - + '&scope=user.read user.write', + // 密码模式的参数 + + "&grant_type=" + grantType + + "&username=" + username + + "&password=" + password + + '&scope=user.read user.write', method: 'POST', headers: { - 'tenant-id': '1', // 多租户编号,写死 + 'tenant-id': '1', // 多租户编号,写死 }, success: function (result) { if (result.code !== 0) { @@ -57,9 +57,9 @@ - 账号:
- 密码:
- +账号:
+密码:
+