From 9b4f5740938b07e7dba38557f5a972f186352fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=91=E5=B0=8F=E9=A9=AC?= Date: Wed, 23 Jul 2025 17:58:06 +0800 Subject: [PATCH] code --- .../lktx/center/config/AuthRequestConfig.java | 36 +++++ .../java/com/lktx/center/config/Data.java | 6 + .../lktx/center/config/SsoAuthRequest.java | 128 ++++++++++++++++++ .../com/lktx/center/config/SsoSource.java | 43 ++++++ .../center/controller/HomeController.java | 70 ++++++++++ .../center/controller/RestAuthController.java | 42 ++++++ .../lktx/center/domain/bean/RemoteRes.java | 10 ++ .../com/lktx/center/domain/bean/SsoApp.java | 32 +++++ .../lktx/center/domain/bean/SsoAppGroup.java | 21 +++ .../com/lktx/center/domain/bean/SsoUser.java | 40 ++++++ .../lktx/center/domain/vo/SsoUserAppVO.java | 13 ++ 11 files changed, 441 insertions(+) create mode 100644 api/src/main/java/com/lktx/center/config/AuthRequestConfig.java create mode 100644 api/src/main/java/com/lktx/center/config/Data.java create mode 100644 api/src/main/java/com/lktx/center/config/SsoAuthRequest.java create mode 100644 api/src/main/java/com/lktx/center/config/SsoSource.java create mode 100644 api/src/main/java/com/lktx/center/controller/HomeController.java create mode 100644 api/src/main/java/com/lktx/center/controller/RestAuthController.java create mode 100644 api/src/main/java/com/lktx/center/domain/bean/RemoteRes.java create mode 100644 api/src/main/java/com/lktx/center/domain/bean/SsoApp.java create mode 100644 api/src/main/java/com/lktx/center/domain/bean/SsoAppGroup.java create mode 100644 api/src/main/java/com/lktx/center/domain/bean/SsoUser.java create mode 100644 api/src/main/java/com/lktx/center/domain/vo/SsoUserAppVO.java diff --git a/api/src/main/java/com/lktx/center/config/AuthRequestConfig.java b/api/src/main/java/com/lktx/center/config/AuthRequestConfig.java new file mode 100644 index 0000000..74c5777 --- /dev/null +++ b/api/src/main/java/com/lktx/center/config/AuthRequestConfig.java @@ -0,0 +1,36 @@ +package com.lktx.center.config; + +import cn.hserver.core.ioc.annotation.Bean; +import cn.hserver.core.ioc.annotation.Configuration; +import cn.hserver.core.ioc.annotation.Value; +import me.zhyd.oauth.config.AuthConfig; + +import java.util.List; + +@Configuration +public class AuthRequestConfig { + + @Value("oauth.clientId") + private String clientId; + + @Value("oauth.clientSecret") + private String clientSecret; + + @Value("oauth.redirectUri") + private String redirectUri; + + @Value("oauth.url") + private String url; + + @Bean + public SsoAuthRequest getAuthRequest() { + return new SsoAuthRequest(AuthConfig.builder() + .clientId(clientId) + .clientSecret(clientSecret) + .redirectUri(redirectUri) + //其他系统可以不要center + .scopes(List.of("userinfo", "center")) + .build(),new SsoSource(url)); + } + +} diff --git a/api/src/main/java/com/lktx/center/config/Data.java b/api/src/main/java/com/lktx/center/config/Data.java new file mode 100644 index 0000000..e487673 --- /dev/null +++ b/api/src/main/java/com/lktx/center/config/Data.java @@ -0,0 +1,6 @@ +package com.lktx.center.config; + + +public interface Data { + String AuthToken = "AuthToken"; +} diff --git a/api/src/main/java/com/lktx/center/config/SsoAuthRequest.java b/api/src/main/java/com/lktx/center/config/SsoAuthRequest.java new file mode 100644 index 0000000..8d288ef --- /dev/null +++ b/api/src/main/java/com/lktx/center/config/SsoAuthRequest.java @@ -0,0 +1,128 @@ +package com.lktx.center.config; + +import com.alibaba.fastjson.JSONObject; +import com.lktx.center.domain.vo.SsoUserAppVO; +import me.zhyd.oauth.cache.AuthStateCache; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.enums.AuthResponseStatus; +import me.zhyd.oauth.enums.AuthUserGender; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthDefaultRequest; +import me.zhyd.oauth.utils.*; + +import java.util.Map; + + +public class SsoAuthRequest extends AuthDefaultRequest { + + private final SsoSource source; + + public SsoAuthRequest(AuthConfig config,SsoSource source) { + super(config, source); + this.source=source; + } + + private AuthToken getAuthToken(JSONObject object) { + this.checkResponse(object); + return AuthToken.builder().accessToken(object.getString("access_token")).expireIn(object.getIntValue("expires_in")).tokenType(object.getString("token_type")).idToken(object.getString("id_token")).refreshToken(object.getString("refresh_token")).uid(object.getString("userId")).openId(object.getString("userId")).build(); + } + + private void checkResponse(JSONObject object) { + if (object.containsKey("error")) { + throw new AuthException(object.getString("error_description")); + } + } + @Override + protected String revokeUrl(AuthToken authToken) { + return UrlBuilder.fromBaseUrl(source.revoke()) + .queryParam("access_token", authToken.getAccessToken()) + .queryParam("client_id", this.config.getClientId()) + .queryParam("client_secret", this.config.getClientSecret()) + .build(); + } + + @Override + public String authorize(String state) { + return UrlBuilder.fromBaseUrl(source.authorize()).queryParam("response_type", "code").queryParam("client_id", this.config.getClientId()).queryParam("redirect_uri", this.config.getRedirectUri()).queryParam("scope", String.join(",",this.config.getScopes())).queryParam("state", this.getRealState(state)).build(); + } + + @Override + public AuthToken getAccessToken(AuthCallback authCallback) { + return AuthToken.builder().accessCode(authCallback.getCode()).build(); + } + + + @Override + public AuthUser getUserInfo(AuthToken authToken) { + String response = this.doPostAuthorizationCode(authToken.getAccessCode()); + JSONObject accessTokenObject = JSONObject.parseObject(response); + if (accessTokenObject.getIntValue("code") != 200) { + throw new AuthException(accessTokenObject.getString("mssg")); + } else { + authToken = this.getAuthToken(accessTokenObject); + return AuthUser.builder().rawUserInfo(accessTokenObject) + .uuid(StringUtils.isEmpty(authToken.getUid()) ? authToken.getOpenId() : authToken.getUid()) + .username(accessTokenObject.getString("username")).nickname(accessTokenObject.getString("nickname")) + .avatar(accessTokenObject.getString("avatar")) + .email(accessTokenObject.getString("email")) + .gender(AuthUserGender.UNKNOWN) + .token(authToken) + .source(source.toString()) + .build(); + } + } + + @Override + public AuthResponse refresh(AuthToken oldToken) { + String tokenUrl = this.refreshTokenUrl(oldToken.getRefreshToken()); + String response = (new HttpUtils(this.config.getHttpConfig())).post(tokenUrl).getBody(); + JSONObject accessTokenObject = JSONObject.parseObject(response); + AuthResponse authTokenAuthResponse = new AuthResponse<>(); + if (accessTokenObject.getIntValue("code") == 200) { + authTokenAuthResponse.setCode(AuthResponseStatus.SUCCESS.getCode()); + authTokenAuthResponse.setData(this.getAuthToken(accessTokenObject)); + }else { + authTokenAuthResponse.setCode(AuthResponseStatus.FAILURE.getCode()); + authTokenAuthResponse.setMsg(accessTokenObject.getString("msg")); + } + + return authTokenAuthResponse; + } + + + @Override + public AuthResponse revoke(AuthToken authToken) { + String tokenUrl = this.revokeUrl(authToken); + String response = (new HttpUtils(this.config.getHttpConfig())).post(tokenUrl).getBody(); + JSONObject accessTokenObject = JSONObject.parseObject(response); + AuthResponse authTokenAuthResponse = new AuthResponse<>(); + authTokenAuthResponse.setMsg(accessTokenObject.getString("msg")); + if (accessTokenObject.getIntValue("code") == 200) { + authTokenAuthResponse.setCode(AuthResponseStatus.SUCCESS.getCode()); + }else { + authTokenAuthResponse.setCode(AuthResponseStatus.FAILURE.getCode()); + } + return authTokenAuthResponse; + } + + + public AuthResponse center(AuthToken authToken) { + String response = (new HttpUtils(this.config.getHttpConfig())).post(source.center(),Map.of("access_token",authToken.getAccessToken()),true).getBody(); + JSONObject accessTokenObject = JSONObject.parseObject(response); + AuthResponse authTokenAuthResponse = new AuthResponse<>(); + authTokenAuthResponse.setMsg(accessTokenObject.getString("msg")); + if (accessTokenObject.getIntValue("code") == 200) { + authTokenAuthResponse.setCode(AuthResponseStatus.SUCCESS.getCode()); + authTokenAuthResponse.setData(accessTokenObject.getObject("data", SsoUserAppVO.class)); + }else { + authTokenAuthResponse.setCode(AuthResponseStatus.FAILURE.getCode()); + } + return authTokenAuthResponse; + } + + +} diff --git a/api/src/main/java/com/lktx/center/config/SsoSource.java b/api/src/main/java/com/lktx/center/config/SsoSource.java new file mode 100644 index 0000000..3b3b6c5 --- /dev/null +++ b/api/src/main/java/com/lktx/center/config/SsoSource.java @@ -0,0 +1,43 @@ +package com.lktx.center.config; + +import me.zhyd.oauth.config.AuthSource; +import me.zhyd.oauth.request.AuthDefaultRequest; + +public class SsoSource implements AuthSource { + + private final String baseUrl; + + public SsoSource(String baseUrl) { + this.baseUrl = baseUrl; + } + + @Override + public String authorize() { + return baseUrl+"oauth2/authorize"; + } + @Override + public String accessToken() { + return baseUrl+"oauth2/token"; + } + @Override + public String userInfo() { + return baseUrl+"oauth2/userinfo"; + } + @Override + public String refresh() { + return baseUrl+"oauth2/refresh"; + } + @Override + public String revoke() { + return baseUrl+"oauth2/revoke"; + } + + public String center(){ + return baseUrl+"oauth2/center"; + } + + @Override + public Class getTargetClass() { + return SsoAuthRequest.class; + } +} \ No newline at end of file diff --git a/api/src/main/java/com/lktx/center/controller/HomeController.java b/api/src/main/java/com/lktx/center/controller/HomeController.java new file mode 100644 index 0000000..ae94d12 --- /dev/null +++ b/api/src/main/java/com/lktx/center/controller/HomeController.java @@ -0,0 +1,70 @@ +package com.lktx.center.controller; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.StpUtil; +import cn.hserver.core.ioc.annotation.Autowired; +import cn.hserver.plugin.web.annotation.Controller; +import cn.hserver.plugin.web.annotation.GET; +import cn.hserver.plugin.web.interfaces.HttpResponse; +import cn.hutool.json.JSONUtil; +import com.lktx.center.config.Data; +import com.lktx.center.config.SsoAuthRequest; +import com.lktx.center.domain.bean.SsoApp; +import com.lktx.center.domain.vo.SsoUserAppVO; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthToken; + +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Controller +public class HomeController { + + @Autowired + private SsoAuthRequest authRequest; + + @GET("/") + public void index(HttpResponse response) { + if (StpUtil.isLogin()){ + try { + SaSession session = StpUtil.getSession(); + AuthToken authToken = session.get(Data.AuthToken,null); + if (authToken != null){ + AuthResponse center = authRequest.center(authToken); + if (center.ok()) { + Map data = Map.of( + "user", center.getData().getSsoUser(), + "appList", center.getData().getSsoAppList(), + "appGroup", center.getData().getSsoAppList().stream().map(SsoApp::getSsoAppGroup).collect(Collectors.toSet()) + ); + response.sendTemplate("index.ftl",data); + } + } + }catch (Exception e){ + //通常是token失效导致的异常返回 + response.redirect("/oauth/render"); + } + }else { + response.redirect("/oauth/render"); + } + } + + + @GET("/logout") + public void logout(HttpResponse response) { + if (StpUtil.isLogin()){ + //可以全局退出 + SaSession session = StpUtil.getSession(); + AuthToken authToken = session.get(Data.AuthToken,null); + if (authToken != null){ + AuthResponse revoke = authRequest.revoke(authToken); + System.out.println(revoke.getMsg()); + } + //子系统退出 + StpUtil.logout(); + } + response.redirect("/"); + } +} diff --git a/api/src/main/java/com/lktx/center/controller/RestAuthController.java b/api/src/main/java/com/lktx/center/controller/RestAuthController.java new file mode 100644 index 0000000..59ea08a --- /dev/null +++ b/api/src/main/java/com/lktx/center/controller/RestAuthController.java @@ -0,0 +1,42 @@ +package com.lktx.center.controller; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.StpUtil; +import cn.hserver.core.ioc.annotation.Autowired; +import cn.hserver.plugin.web.annotation.Controller; +import cn.hserver.plugin.web.annotation.RequestMapping; +import cn.hserver.plugin.web.interfaces.HttpResponse; +import com.lktx.center.config.Data; +import com.lktx.center.config.SsoAuthRequest; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.utils.AuthStateUtils; + +@Controller("/oauth") +public class RestAuthController { + + @Autowired + private SsoAuthRequest authRequest; + + @RequestMapping("/render") + public void renderAuth(HttpResponse response) { + String authorize = authRequest.authorize(AuthStateUtils.createState()); + response.redirect(authorize); + } + + @RequestMapping("/callback") + public void login(AuthCallback callback,HttpResponse response) { + try { + AuthResponse login = authRequest.login(callback); + AuthToken token = login.getData().getToken(); + StpUtil.login(login.getData().getUuid()); + SaSession session = StpUtil.getSession(); + session.set(Data.AuthToken, token); + response.redirect("/"); + }catch (Exception e) { + response.redirect("/"); + } + } +} \ No newline at end of file diff --git a/api/src/main/java/com/lktx/center/domain/bean/RemoteRes.java b/api/src/main/java/com/lktx/center/domain/bean/RemoteRes.java new file mode 100644 index 0000000..3132695 --- /dev/null +++ b/api/src/main/java/com/lktx/center/domain/bean/RemoteRes.java @@ -0,0 +1,10 @@ +package com.lktx.center.domain.bean; + +import lombok.Data; + +@Data +public class RemoteRes{ + private Integer code; + private String msg; + private T data; +} diff --git a/api/src/main/java/com/lktx/center/domain/bean/SsoApp.java b/api/src/main/java/com/lktx/center/domain/bean/SsoApp.java new file mode 100644 index 0000000..5a039d2 --- /dev/null +++ b/api/src/main/java/com/lktx/center/domain/bean/SsoApp.java @@ -0,0 +1,32 @@ +package com.lktx.center.domain.bean; + +import lombok.Data; +import me.zhyd.oauth.utils.UrlBuilder; + +import java.time.LocalDateTime; + +/** app分组 - sso_app */ +@Data +public class SsoApp { + /**appId*/ + private Integer ssoAppId; + /**app分组*/ + private Integer ssoAppGroupId; + /**备注*/ + private String remark; + /**创建时间*/ + private Integer status; + /**客户端ID*/ + private String clientId; + /**客户端秘钥*/ + private String clientSecret; + /**app名字*/ + private String appName; + /**app图片地址*/ + private String appIcon; + /**APP类型*/ + private String appType; + private String appUrl; + private SsoAppGroup ssoAppGroup; + +} \ No newline at end of file diff --git a/api/src/main/java/com/lktx/center/domain/bean/SsoAppGroup.java b/api/src/main/java/com/lktx/center/domain/bean/SsoAppGroup.java new file mode 100644 index 0000000..5ab384d --- /dev/null +++ b/api/src/main/java/com/lktx/center/domain/bean/SsoAppGroup.java @@ -0,0 +1,21 @@ +package com.lktx.center.domain.bean; + + +import lombok.Data; + +import java.time.LocalDateTime; + +/** app分组 - sso_app_group */ +@Data +public class SsoAppGroup { + /**分组ID*/ + private Integer ssoAppGroupId; + /**分组名字*/ + private String name; + /**备注*/ + private String remark; + /**创建时间*/ + private LocalDateTime createTime; + /**更新时间*/ + private LocalDateTime updateTime; +} \ No newline at end of file diff --git a/api/src/main/java/com/lktx/center/domain/bean/SsoUser.java b/api/src/main/java/com/lktx/center/domain/bean/SsoUser.java new file mode 100644 index 0000000..bf657d4 --- /dev/null +++ b/api/src/main/java/com/lktx/center/domain/bean/SsoUser.java @@ -0,0 +1,40 @@ +package com.lktx.center.domain.bean; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** SSO用户表 - sso_user */ +@Data +public class SsoUser { + private Integer ssoUserId; + /*组织ID*/ + private Integer ssoOrganizationId; + /**头像*/ + private String avatar; + /**用户姓名*/ + private String name; + /**用户昵称*/ + private String nickname; + /**用户登录名*/ + private String username; + /**手机号*/ + private String phone; + /**邮箱*/ + private String email; + /**密码*/ + private String password; + /**来源*/ + private String source; + /**是否冻结 0 启用 1 禁用*/ + private Integer locked; + /**用户描述*/ + private String remark; + /**是否逻辑删除*/ + private Integer deleted; + /**创建时间*/ + private LocalDateTime createTime; + /**更新时间*/ + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/api/src/main/java/com/lktx/center/domain/vo/SsoUserAppVO.java b/api/src/main/java/com/lktx/center/domain/vo/SsoUserAppVO.java new file mode 100644 index 0000000..6e3c585 --- /dev/null +++ b/api/src/main/java/com/lktx/center/domain/vo/SsoUserAppVO.java @@ -0,0 +1,13 @@ +package com.lktx.center.domain.vo; + +import com.lktx.center.domain.bean.SsoApp; +import com.lktx.center.domain.bean.SsoUser; +import lombok.Data; + +import java.util.List; + +@Data +public class SsoUserAppVO { + private SsoUser ssoUser; + private List ssoAppList; +}