From cd0aace6dcfb15cf0f35419b0c38732160cbff97 Mon Sep 17 00:00:00 2001 From: Wang Date: Wed, 31 Dec 2025 17:34:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BB=A3=E7=90=86=E5=95=86?= =?UTF-8?q?=EF=BC=8C=E6=B4=BB=E5=8A=A8=EF=BC=8C=E4=BB=A3=E7=90=86=E5=95=86?= =?UTF-8?q?=E5=91=98=E5=B7=A5=E5=85=B3=EF=BC=8C=E4=BB=A3=E7=90=86=E5=95=86?= =?UTF-8?q?=E6=B4=BB=E5=8A=A8=E5=8F=82=E4=B8=8E=E8=80=85=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- seer-gateway/pom.xml | 3 +- .../seer/teach/filter/cors/CorsConfig.java | 49 ++++++++++++ .../seer/teach/filter/cors/CorsFilter.java | 10 ++- .../filter/cors/CorsResponseHeaderFilter.java | 50 +++++++++++++ .../src/main/resources/application.yml | 20 ++++- .../controller/AdminMpAccountController.java | 4 +- .../admin/service/AdminMpAccountService.java | 4 +- .../controller/req/MpGenerateQrCodeReq.java | 9 ++- .../app/service/AppOfficialQrCodeService.java | 9 ++- .../src/main/resources/application.yml | 6 +- .../seer/teach/user/app/auth/LoginType.java | 7 +- .../auth/controller/AppAuthController.java | 4 +- ...{WeChatLoginParam.java => LoginParam.java} | 20 ++--- .../user/app/auth/service/AppAuthService.java | 4 +- .../user/app/auth/service/LoginStrategy.java | 4 +- .../user/app/auth/service/LoginUser.java | 4 + .../strategy/MiniProgramLoginStrategy.java | 6 +- .../OfficialAccountLoginStrategy.java | 8 +- ...OfficialOauthWithAccountLoginStrategy.java | 75 +++++++++++++++++++ .../WarehouseAccountLoginStrategy.java | 4 +- .../WechatChildrenAccountLoginStrategy.java | 4 +- .../user/controller/resp/AppUserInfoResp.java | 2 + .../teach/user/service/IUserRoleService.java | 13 ++++ .../service/impl/UserRoleServiceImpl.java | 13 ++++ 24 files changed, 291 insertions(+), 41 deletions(-) create mode 100644 seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsConfig.java create mode 100644 seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsResponseHeaderFilter.java rename seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/request/{WeChatLoginParam.java => LoginParam.java} (72%) create mode 100644 seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/OfficialOauthWithAccountLoginStrategy.java diff --git a/seer-gateway/pom.xml b/seer-gateway/pom.xml index d408cd2..4361787 100644 --- a/seer-gateway/pom.xml +++ b/seer-gateway/pom.xml @@ -75,8 +75,7 @@ ${basedir}/src/main/resources - **.xml - **.yml + ** diff --git a/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsConfig.java b/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsConfig.java new file mode 100644 index 0000000..d763c24 --- /dev/null +++ b/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsConfig.java @@ -0,0 +1,49 @@ +package com.seer.teach.filter.cors; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.reactive.CorsWebFilter; +import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; +import org.springframework.web.util.pattern.PathPatternParser; + +import java.util.ArrayList; +import java.util.List; + +@Configuration +public class CorsConfig { + + @Bean + @ConfigurationProperties(prefix = "zs.cors") + public Cors cors() { + return new Cors(); + } + + @Bean + public CorsWebFilter corsWebFilter(Cors cors) { + CorsConfiguration config = new CorsConfiguration(); + config.setAllowedOriginPatterns(cors.getOrigins()); + // 允许的HTTP方法 + config.addAllowedMethod("*"); + // 允许的请求头 + config.addAllowedHeader("*"); + config.setAllowCredentials(true); + // 暴露的响应头 + config.addExposedHeader("token"); + config.addExposedHeader("Content-Disposition"); + config.setMaxAge(3600L); + UrlBasedCorsConfigurationSource source = + new UrlBasedCorsConfigurationSource(new PathPatternParser()); + source.registerCorsConfiguration("/**", config); + return new CorsWebFilter(source); + } + + @Getter + @Setter + public static class Cors { + private List origins = new ArrayList<>(); + } +} diff --git a/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsFilter.java b/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsFilter.java index 3aaa01b..eadb9b8 100644 --- a/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsFilter.java +++ b/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsFilter.java @@ -1,8 +1,10 @@ package com.seer.teach.filter.cors; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; +import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; @@ -13,7 +15,7 @@ import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; - +@Slf4j @Component public class CorsFilter implements WebFilter { @@ -23,17 +25,21 @@ public class CorsFilter implements WebFilter { public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); if (!CorsUtils.isCorsRequest(request)) { + log.info("Not a CORS request"); return chain.filter(exchange); } - + RequestPath path = exchange.getRequest().getPath(); + log.info("request path: {},method : {}", path, request.getMethod()); ServerHttpResponse response = exchange.getResponse(); HttpHeaders headers = response.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, CorsConfiguration.ALL); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, CorsConfiguration.ALL); + headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, CorsConfiguration.ALL); headers.add(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, CorsConfiguration.ALL); headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); + log.info("CORS preflight request,OK"); return Mono.empty(); } return chain.filter(exchange); diff --git a/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsResponseHeaderFilter.java b/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsResponseHeaderFilter.java new file mode 100644 index 0000000..fe9f19f --- /dev/null +++ b/seer-gateway/src/main/java/com/seer/teach/filter/cors/CorsResponseHeaderFilter.java @@ -0,0 +1,50 @@ +package com.seer.teach.filter.cors; + +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter; +import org.springframework.core.Ordered; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 解决 Spring Cloud Gateway 2.x 跨域时,出现重复 Origin 的 BUG + * + * 参考文档: + * + */ +@Component +public class CorsResponseHeaderFilter implements GlobalFilter, Ordered { + + @Override + public int getOrder() { + return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1; + } + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + return chain.filter(exchange).then(Mono.defer(() -> { + List keysToModify = exchange.getResponse().getHeaders().entrySet().stream() + .filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1)) + .filter(kv -> (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) + || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS))) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + keysToModify.forEach(key->{ + List values = exchange.getResponse().getHeaders().get(key); + if (values != null && !values.isEmpty()) { + exchange.getResponse().getHeaders().put(key, Collections.singletonList(values.get(0))); + } + }); + return chain.filter(exchange); + })); + } + +} diff --git a/seer-gateway/src/main/resources/application.yml b/seer-gateway/src/main/resources/application.yml index f84994c..631cf5b 100644 --- a/seer-gateway/src/main/resources/application.yml +++ b/seer-gateway/src/main/resources/application.yml @@ -81,4 +81,22 @@ logging: level: org.springframework.cloud.gateway: DEBUG # 查看 Gateway 过滤器链 org.springframework.security: DEBUG # 检查 Spring Security 拦截 - reactor.netty.http.client: DEBUG # 查看网络层交互 \ No newline at end of file + reactor.netty.http.client: DEBUG # 查看网络层交互 + + +zs: + decryption: + enabled: true + encryption: + enabled: true + cors: + origins: + - http://localhost:* + - http://192.168.*:* + - http://10.10.*:* + - http://10.10.4.143:8020 + - http://10.10.3.134:8020 + - https://admin-api.seerteach.net:* + - http://admin-api.seerteach.net:* + - https://admin.seerteach.net:* + - https://admin.seerteach.net \ No newline at end of file diff --git a/seer-mp/seer-mp-service-admin/src/main/java/com/seer/teach/mp/admin/controller/AdminMpAccountController.java b/seer-mp/seer-mp-service-admin/src/main/java/com/seer/teach/mp/admin/controller/AdminMpAccountController.java index 6ca8c03..73dace7 100644 --- a/seer-mp/seer-mp-service-admin/src/main/java/com/seer/teach/mp/admin/controller/AdminMpAccountController.java +++ b/seer-mp/seer-mp-service-admin/src/main/java/com/seer/teach/mp/admin/controller/AdminMpAccountController.java @@ -76,7 +76,7 @@ public class AdminMpAccountController { @PostMapping("/generate-qr-code") @Operation(summary = "生成公众号二维码") @SaCheckPermission("admin:mp:account:qr-code'") - public ResultBean generateAccountQrCode(@RequestParam("id") Integer id) { - return ResultBean.success(mpAccountService.generateAccountQrCode(id)); + public ResultBean generateAccountQrCode(@RequestParam("id") Integer id,@RequestParam("场景值") String sceneStr) { + return ResultBean.success(mpAccountService.generateAccountQrCode(id,sceneStr)); } } \ No newline at end of file diff --git a/seer-mp/seer-mp-service-admin/src/main/java/com/seer/teach/mp/admin/service/AdminMpAccountService.java b/seer-mp/seer-mp-service-admin/src/main/java/com/seer/teach/mp/admin/service/AdminMpAccountService.java index c755dbb..df97661 100644 --- a/seer-mp/seer-mp-service-admin/src/main/java/com/seer/teach/mp/admin/service/AdminMpAccountService.java +++ b/seer-mp/seer-mp-service-admin/src/main/java/com/seer/teach/mp/admin/service/AdminMpAccountService.java @@ -141,12 +141,12 @@ public class AdminMpAccountService { * @param id 公众号账号ID * @return 是否生成成功 */ - public Boolean generateAccountQrCode(Integer id) { + public Boolean generateAccountQrCode(Integer id,String sceneStr) { MpAccountEntity account = mpAccountService.getById(id); WxMpService mpService = mpServiceFactory.getRequiredMpService(account.getAppId()); String qrCodeUrl; try { - WxMpQrCodeTicket qrCodeTicket = mpService.getQrcodeService().qrCodeCreateLastTicket("default"); + WxMpQrCodeTicket qrCodeTicket = mpService.getQrcodeService().qrCodeCreateLastTicket(sceneStr); qrCodeUrl = mpService.getQrcodeService().qrCodePictureUrl(qrCodeTicket.getTicket()); } catch (WxErrorException e) { log.error("生成公众号二维码失败", e); diff --git a/seer-mp/seer-mp-service-app/src/main/java/com/seer/teach/mp/app/controller/req/MpGenerateQrCodeReq.java b/seer-mp/seer-mp-service-app/src/main/java/com/seer/teach/mp/app/controller/req/MpGenerateQrCodeReq.java index 1f5fadc..f73fe0e 100644 --- a/seer-mp/seer-mp-service-app/src/main/java/com/seer/teach/mp/app/controller/req/MpGenerateQrCodeReq.java +++ b/seer-mp/seer-mp-service-app/src/main/java/com/seer/teach/mp/app/controller/req/MpGenerateQrCodeReq.java @@ -7,7 +7,12 @@ import lombok.Data; @Data public class MpGenerateQrCodeReq { - private String userId; + @Schema(description = "场景值") + private String sceneStr; + @Schema(description = "小程序appid") private String appId; -} + + @Schema(description = "二维码类型 1-临时 2-永久") + private Integer type; +} \ No newline at end of file diff --git a/seer-mp/seer-mp-service-app/src/main/java/com/seer/teach/mp/app/service/AppOfficialQrCodeService.java b/seer-mp/seer-mp-service-app/src/main/java/com/seer/teach/mp/app/service/AppOfficialQrCodeService.java index 4ea30ed..acf420f 100644 --- a/seer-mp/seer-mp-service-app/src/main/java/com/seer/teach/mp/app/service/AppOfficialQrCodeService.java +++ b/seer-mp/seer-mp-service-app/src/main/java/com/seer/teach/mp/app/service/AppOfficialQrCodeService.java @@ -8,6 +8,7 @@ import com.seer.teach.mp.factory.MpServiceFactory; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpQrcodeService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; import org.springframework.beans.factory.annotation.Value; @@ -30,8 +31,14 @@ public class AppOfficialQrCodeService { WxMpService wxMpService = mpServiceFactory.getRequiredMpService(req.getAppId()); Integer expireSeconds = mpQrCodeExpireTime * 60 *60; - WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(req.getUserId(), expireSeconds);; + WxMpQrcodeService qrcodeService = wxMpService.getQrcodeService(); + WxMpQrCodeTicket ticket; + if(req.getType() == 1) { + ticket = qrcodeService.qrCodeCreateTmpTicket(req.getSceneStr(), expireSeconds); + }else{ + ticket = qrcodeService.qrCodeCreateLastTicket(req.getSceneStr()); + } String qrCodeUrl = wxMpService.getQrcodeService().qrCodePictureUrl(ticket.getTicket()); MpQrCodeResp resp = new MpQrCodeResp(); diff --git a/seer-user/seer-user-service-app-bootstrap/src/main/resources/application.yml b/seer-user/seer-user-service-app-bootstrap/src/main/resources/application.yml index 5830cae..b79c372 100644 --- a/seer-user/seer-user-service-app-bootstrap/src/main/resources/application.yml +++ b/seer-user/seer-user-service-app-bootstrap/src/main/resources/application.yml @@ -48,4 +48,8 @@ zs: decryption: enabled: false encryption: - enabled: false \ No newline at end of file + enabled: false + cors: + origins: + - http://10.10.3.134:8020 + - http://10.10.4.143:8020 \ No newline at end of file diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/LoginType.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/LoginType.java index 229a7a5..6fa7ef0 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/LoginType.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/LoginType.java @@ -22,7 +22,12 @@ public enum LoginType { /** * 仓库登录 */ - WAREHOUSE_ACCOUNT("warehouse_account", "仓库登录"); + WAREHOUSE_ACCOUNT("warehouse_account", "仓库登录"), + + /** + * 微信公众号账号密码登录 + */ + WECHAT_OAUTH_WITH_ACCOUNT("wechat_oauth_with_account", "微信公众号账号密码登录"); private String code; diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/controller/AppAuthController.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/controller/AppAuthController.java index 88142f6..95b4250 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/controller/AppAuthController.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/controller/AppAuthController.java @@ -10,7 +10,7 @@ import com.seer.teach.common.annotation.EncryptionAnnotation; import com.seer.teach.common.annotation.LogOperation; import com.seer.teach.common.annotation.LogPrint; import com.seer.teach.common.enums.ModuleEnum; -import com.seer.teach.user.app.auth.request.WeChatLoginParam; +import com.seer.teach.user.app.auth.request.LoginParam; import com.seer.teach.user.app.auth.response.LoginResp; import com.seer.teach.user.app.auth.service.AppAuthService; import io.swagger.v3.oas.annotations.tags.Tag; @@ -37,7 +37,7 @@ public class AppAuthController { private AppAuthService userAuthService; @PostMapping("/login") - public ResultBean login(@RequestBody WeChatLoginParam request) { + public ResultBean login(@RequestBody LoginParam request) { return ResultBean.success(userAuthService.authenticate(request)); } diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/request/WeChatLoginParam.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/request/LoginParam.java similarity index 72% rename from seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/request/WeChatLoginParam.java rename to seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/request/LoginParam.java index b4041c8..641f819 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/request/WeChatLoginParam.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/request/LoginParam.java @@ -2,24 +2,24 @@ package com.seer.teach.user.app.auth.request; import com.seer.teach.user.app.auth.LoginType; import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; - import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + -/** - * @Author: Captain - * @Description: 微信小程序登录请求参数 - * @Date: 2025-05-19 17:46 - */ @Data @AllArgsConstructor @NoArgsConstructor @ToString @Builder -@Schema(description = "微信登录请求实体类") -public class WeChatLoginParam { +@Schema(description = "登录请求实体类") +public class LoginParam { + @Schema(description = "登录方式不可为空") + @NotBlank(message = "loginType不可为空") LoginType loginType; @Schema(description = "jsCode不可为空") diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/AppAuthService.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/AppAuthService.java index 8aae263..eccd194 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/AppAuthService.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/AppAuthService.java @@ -5,7 +5,7 @@ import cn.hutool.core.collection.CollectionUtil; import com.seer.teach.common.enums.ResultCodeEnum; import com.seer.teach.common.utils.AssertUtils; import com.seer.teach.user.app.auth.LoginType; -import com.seer.teach.user.app.auth.request.WeChatLoginParam; +import com.seer.teach.user.app.auth.request.LoginParam; import com.seer.teach.user.app.auth.response.LoginResp; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -43,7 +43,7 @@ public class AppAuthService { * @return */ @Transactional(rollbackFor = Exception.class,timeout = 120) - public LoginResp authenticate(WeChatLoginParam request) { + public LoginResp authenticate(LoginParam request) { LoginStrategy strategy = strategyMap.get(request.getLoginType()); AssertUtils.notNull(strategy, ResultCodeEnum.LOGIN_TYPE_ERROR); diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/LoginStrategy.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/LoginStrategy.java index c168623..0b8629d 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/LoginStrategy.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/LoginStrategy.java @@ -1,7 +1,7 @@ package com.seer.teach.user.app.auth.service; import com.seer.teach.user.app.auth.LoginType; -import com.seer.teach.user.app.auth.request.WeChatLoginParam; +import com.seer.teach.user.app.auth.request.LoginParam; public interface LoginStrategy { @@ -13,5 +13,5 @@ public interface LoginStrategy { * @param request * @return */ - LoginUser authenticate(WeChatLoginParam request); + LoginUser authenticate(LoginParam request); } diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/LoginUser.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/LoginUser.java index 9429260..d8f45c4 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/LoginUser.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/LoginUser.java @@ -2,6 +2,8 @@ package com.seer.teach.user.app.auth.service; import lombok.Data; +import java.util.List; + @Data public class LoginUser { @@ -17,6 +19,8 @@ public class LoginUser { */ private Integer applyStatus; + private List roles; + public LoginUser(Integer userId) { this.userId = userId; } diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/MiniProgramLoginStrategy.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/MiniProgramLoginStrategy.java index 6997e4b..66c3893 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/MiniProgramLoginStrategy.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/MiniProgramLoginStrategy.java @@ -11,7 +11,7 @@ import com.seer.teach.common.utils.AssertUtils; import com.seer.teach.mp.api.WechatMiniProgramApi; import com.seer.teach.mp.api.resp.WxMiniProgramSessionDTO; import com.seer.teach.user.app.auth.LoginType; -import com.seer.teach.user.app.auth.request.WeChatLoginParam; +import com.seer.teach.user.app.auth.request.LoginParam; import com.seer.teach.user.app.auth.service.LoginStrategy; import com.seer.teach.user.app.auth.service.LoginUser; import com.seer.teach.user.entity.UserAuthEntity; @@ -69,7 +69,7 @@ public class MiniProgramLoginStrategy extends AbstractLoginStrategy implements L } @Override - public LoginUser authenticate(WeChatLoginParam request) { + public LoginUser authenticate(LoginParam request) { WxMiniProgramSessionDTO wxMiniProgramSessionDTO = wechatMiniProgramApi.code2Session(request.getJsCode()); AssertUtils.isTrue(wxMiniProgramSessionDTO.isSuccess(), ResultCodeEnum.WX_OAUTH_USED_ERROR); UserAuthEntity userAuth = userAuthService.getOneByOpenIdAndUnionId(wxMiniProgramSessionDTO.getOpenid(), wxMiniProgramSessionDTO.getUnionid()); @@ -156,7 +156,7 @@ public class MiniProgramLoginStrategy extends AbstractLoginStrategy implements L * @param request 登录参数 * @return boolean true 是扫码登录,false 密码登录 */ - private boolean isScanQrCodeLogin(WeChatLoginParam request) { + private boolean isScanQrCodeLogin(LoginParam request) { if (!StringUtils.hasText(request.getScene())) { return false; } diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/OfficialAccountLoginStrategy.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/OfficialAccountLoginStrategy.java index e8f8b9a..113a22a 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/OfficialAccountLoginStrategy.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/OfficialAccountLoginStrategy.java @@ -5,7 +5,7 @@ import com.seer.teach.common.utils.AssertUtils; import com.seer.teach.mp.api.WechatOfficialAccountApi; import com.seer.teach.mp.api.resp.WxOAuth2AccessTokenDTO; import com.seer.teach.user.app.auth.LoginType; -import com.seer.teach.user.app.auth.request.WeChatLoginParam; +import com.seer.teach.user.app.auth.request.LoginParam; import com.seer.teach.user.app.auth.service.LoginStrategy; import com.seer.teach.user.app.auth.service.LoginUser; import com.seer.teach.user.entity.UserAuthEntity; @@ -28,7 +28,6 @@ public class OfficialAccountLoginStrategy extends AbstractLoginStrategy implemen @Autowired private WechatOfficialAccountApi wechatOfficialAccountApi; - @Autowired private IUserService userService; @@ -41,7 +40,7 @@ public class OfficialAccountLoginStrategy extends AbstractLoginStrategy implemen } @Override - public LoginUser authenticate(WeChatLoginParam request) { + public LoginUser authenticate(LoginParam request) { log.info("微信公众号登录:{}",request); WxOAuth2AccessTokenDTO wxOAuth2AccessToken = wechatOfficialAccountApi.getUserWxOAuth2AccessToken(request.getAppId(), request.getJsCode()); log.debug("获取用户信息:{}",wxOAuth2AccessToken); @@ -61,7 +60,8 @@ public class OfficialAccountLoginStrategy extends AbstractLoginStrategy implemen }else{ userAuth.setAppId(request.getAppId()); updateUserAuth(userAuth); + LoginUser loginUser = new LoginUser(userAuth.getUserId()); + return loginUser; } - return new LoginUser(userAuth.getUserId()); } } \ No newline at end of file diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/OfficialOauthWithAccountLoginStrategy.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/OfficialOauthWithAccountLoginStrategy.java new file mode 100644 index 0000000..9714a41 --- /dev/null +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/OfficialOauthWithAccountLoginStrategy.java @@ -0,0 +1,75 @@ +package com.seer.teach.user.app.auth.service.strategy; + +import cn.dev33.satoken.stp.StpUtil; +import com.seer.teach.common.enums.ResultCodeEnum; +import com.seer.teach.common.exception.CommonException; +import com.seer.teach.common.utils.AssertUtils; +import com.seer.teach.common.utils.CommonUtils; +import com.seer.teach.mp.api.WechatOfficialAccountApi; +import com.seer.teach.mp.api.resp.WxOAuth2AccessTokenDTO; +import com.seer.teach.user.app.auth.LoginType; +import com.seer.teach.user.app.auth.request.LoginParam; +import com.seer.teach.user.app.auth.service.LoginStrategy; +import com.seer.teach.user.app.auth.service.LoginUser; +import com.seer.teach.user.entity.UserAuthEntity; +import com.seer.teach.user.entity.UserEntity; +import com.seer.teach.user.service.IUserService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +/** + * 账号密码登录策略 + * 实现传统的用户名/手机号和密码登录,并生成token + */ +@RequiredArgsConstructor +@Service +@Slf4j +public class OfficialOauthWithAccountLoginStrategy extends AbstractLoginStrategy implements LoginStrategy { + + private final IUserService userService; + + @Autowired + private WechatOfficialAccountApi wechatOfficialAccountApi; + + @Override + public LoginType getType() { + return LoginType.WECHAT_OAUTH_WITH_ACCOUNT; + } + + @Override + public LoginUser authenticate(LoginParam request) { + UserEntity accountUser = null; + if (request.getUserName() != null && !request.getUserName().isEmpty()) { + accountUser = userService.getOneByUserName(request.getUserName()); + } else if (request.getPhoneNumber() != null && !request.getPhoneNumber().isEmpty()) { + accountUser = userService.getOneByMobile(request.getPhoneNumber()); + } + AssertUtils.notNull(accountUser, ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR); + String password = CommonUtils.encryptPassword(request.getPassword()); + if (password.equals(accountUser.getPassword())) { + WxOAuth2AccessTokenDTO wxOAuth2AccessToken = wechatOfficialAccountApi.getUserWxOAuth2AccessToken(request.getAppId(), request.getJsCode()); + log.debug("获取用户信息:{}",wxOAuth2AccessToken); + AssertUtils.notNull(wxOAuth2AccessToken, ResultCodeEnum.WX_OAUTH_USED_ERROR); + String userOpenId = wxOAuth2AccessToken.getOpenId(); + UserAuthEntity userAuth = userAuthService.getOneByOpenId(userOpenId); + StpUtil.login(accountUser.getId()); + if(Objects.isNull(userAuth)){ + boolean userAuthSaved = saveUserAuth(getType().getCode(), accountUser.getId(), wxOAuth2AccessToken, request.getAppId()); + log.info("保存用户授权信息:{}", userAuthSaved); + }else{ + userAuth.setAppId(request.getAppId()); + updateUserAuth(userAuth); + } + log.info("用户[{}]账号密码登录成功", accountUser.getId()); + return new LoginUser(accountUser.getId()); + }else{ + log.info("用户[{}]账号密码登录失败", accountUser.getId()); + throw new CommonException(ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR); + } + + } +} \ No newline at end of file diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/WarehouseAccountLoginStrategy.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/WarehouseAccountLoginStrategy.java index b06251c..a3765d3 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/WarehouseAccountLoginStrategy.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/WarehouseAccountLoginStrategy.java @@ -8,7 +8,7 @@ import com.seer.teach.common.utils.CommonUtils; import com.seer.teach.mp.api.WechatOfficialAccountApi; import com.seer.teach.mp.api.resp.WxOAuth2AccessTokenDTO; import com.seer.teach.user.app.auth.LoginType; -import com.seer.teach.user.app.auth.request.WeChatLoginParam; +import com.seer.teach.user.app.auth.request.LoginParam; import com.seer.teach.user.app.auth.service.LoginStrategy; import com.seer.teach.user.app.auth.service.LoginUser; import com.seer.teach.user.entity.RoleEntity; @@ -52,7 +52,7 @@ public class WarehouseAccountLoginStrategy extends AbstractLoginStrategy impleme } @Override - public LoginUser authenticate(WeChatLoginParam request) { + public LoginUser authenticate(LoginParam request) { AssertUtils.notNull(request.getPassword(), ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR); UserEntity accountUser = userService.getOneByUserName(request.getUserName()); AssertUtils.notNull(accountUser, ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR); diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/WechatChildrenAccountLoginStrategy.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/WechatChildrenAccountLoginStrategy.java index 44c0332..1c99f41 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/WechatChildrenAccountLoginStrategy.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/auth/service/strategy/WechatChildrenAccountLoginStrategy.java @@ -9,7 +9,7 @@ import com.seer.teach.iot.api.UserDeviceServiceApi; import com.seer.teach.mp.api.WechatMiniProgramApi; import com.seer.teach.mp.api.resp.WxMiniProgramSessionDTO; import com.seer.teach.user.app.auth.LoginType; -import com.seer.teach.user.app.auth.request.WeChatLoginParam; +import com.seer.teach.user.app.auth.request.LoginParam; import com.seer.teach.user.app.auth.service.LoginStrategy; import com.seer.teach.user.app.auth.service.LoginUser; import com.seer.teach.user.entity.UserAuthEntity; @@ -49,7 +49,7 @@ public class WechatChildrenAccountLoginStrategy extends AbstractLoginStrategy im } @Override - public LoginUser authenticate(WeChatLoginParam request) { + public LoginUser authenticate(LoginParam request) { UserEntity accountUser =userService.getOneByMobile(request.getPhoneNumber()); AssertUtils.notNull(accountUser, ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR); String password = CommonUtils.encryptPassword(request.getPassword()); diff --git a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/user/controller/resp/AppUserInfoResp.java b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/user/controller/resp/AppUserInfoResp.java index 2655c9b..55cf11b 100644 --- a/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/user/controller/resp/AppUserInfoResp.java +++ b/seer-user/seer-user-service-app/src/main/java/com/seer/teach/user/app/user/controller/resp/AppUserInfoResp.java @@ -55,4 +55,6 @@ public class AppUserInfoResp { @Schema(description = "是否是主监护人") private boolean isPrimaryGuardian; + + } \ No newline at end of file diff --git a/seer-user/seer-user-service/src/main/java/com/seer/teach/user/service/IUserRoleService.java b/seer-user/seer-user-service/src/main/java/com/seer/teach/user/service/IUserRoleService.java index d1ae265..c5b8236 100644 --- a/seer-user/seer-user-service/src/main/java/com/seer/teach/user/service/IUserRoleService.java +++ b/seer-user/seer-user-service/src/main/java/com/seer/teach/user/service/IUserRoleService.java @@ -18,8 +18,21 @@ import java.util.Set; */ public interface IUserRoleService extends IService { + /** + * 根据用户ID获取用户角色列表 + * + * @param userId 用户ID + * @return 用户角色列表 + */ List getListByUserId(Integer userId); + /** + * 获取用户角色编码列表 + * + * @param userId 用户编号 + * @return 角色编码列表 + */ + List getRoleCodeListByUserId(Integer userId); /** * 为用户分配角色 diff --git a/seer-user/seer-user-service/src/main/java/com/seer/teach/user/service/impl/UserRoleServiceImpl.java b/seer-user/seer-user-service/src/main/java/com/seer/teach/user/service/impl/UserRoleServiceImpl.java index bf16d5a..6f2a8d2 100644 --- a/seer-user/seer-user-service/src/main/java/com/seer/teach/user/service/impl/UserRoleServiceImpl.java +++ b/seer-user/seer-user-service/src/main/java/com/seer/teach/user/service/impl/UserRoleServiceImpl.java @@ -44,6 +44,19 @@ public class UserRoleServiceImpl extends ServiceImpl(UserRoleEntity.class).eq(UserRoleEntity::getUserId, userId)); } + @Override + public List getRoleCodeListByUserId(Integer userId) { + List userRoleList = this.getListByUserId(userId); + if(CollectionUtil.isNotEmpty(userRoleList)){ + List roleIds = userRoleList.stream().map(UserRoleEntity::getRoleId).collect(Collectors.toList()); + if(CollectionUtil.isNotEmpty(roleIds)){ + Collection roles = roleService.getRoleListByRoleIds(roleIds); + return roles.stream().map(RoleEntity::getRoleCode).collect(Collectors.toList()); + } + } + return List.of(); + } + @Override public void assignUserRole(Integer userId, Set roleIds) { List userRoleList = this.getListByUserId(userId);