Compare commits
3 Commits
9010154067
...
6e14a9683b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e14a9683b | ||
|
|
814058eea7 | ||
| cd0aace6dc |
@ -75,8 +75,7 @@
|
|||||||
<resource>
|
<resource>
|
||||||
<directory>${basedir}/src/main/resources</directory>
|
<directory>${basedir}/src/main/resources</directory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**.xml</include>
|
<include>**</include>
|
||||||
<include>**.yml</include>
|
|
||||||
</includes>
|
</includes>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@ -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<String> origins = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,10 @@
|
|||||||
package com.seer.teach.filter.cors;
|
package com.seer.teach.filter.cors;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.server.RequestPath;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -13,7 +15,7 @@ import org.springframework.web.server.WebFilter;
|
|||||||
import org.springframework.web.server.WebFilterChain;
|
import org.springframework.web.server.WebFilterChain;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class CorsFilter implements WebFilter {
|
public class CorsFilter implements WebFilter {
|
||||||
|
|
||||||
@ -23,17 +25,21 @@ public class CorsFilter implements WebFilter {
|
|||||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||||
ServerHttpRequest request = exchange.getRequest();
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
if (!CorsUtils.isCorsRequest(request)) {
|
if (!CorsUtils.isCorsRequest(request)) {
|
||||||
|
log.info("Not a CORS request");
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
}
|
}
|
||||||
|
RequestPath path = exchange.getRequest().getPath();
|
||||||
|
log.info("request path: {},method : {}", path, request.getMethod());
|
||||||
ServerHttpResponse response = exchange.getResponse();
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
HttpHeaders headers = response.getHeaders();
|
HttpHeaders headers = response.getHeaders();
|
||||||
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, CorsConfiguration.ALL);
|
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, CorsConfiguration.ALL);
|
||||||
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, 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_REQUEST_HEADERS, CorsConfiguration.ALL);
|
||||||
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
|
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
|
||||||
if (request.getMethod() == HttpMethod.OPTIONS) {
|
if (request.getMethod() == HttpMethod.OPTIONS) {
|
||||||
response.setStatusCode(HttpStatus.OK);
|
response.setStatusCode(HttpStatus.OK);
|
||||||
|
log.info("CORS preflight request,OK");
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}
|
}
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
|
|||||||
@ -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
|
||||||
|
*
|
||||||
|
* 参考文档:<a href="https://blog.csdn.net/zimou5581/article/details/90043178" />
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
return chain.filter(exchange).then(Mono.defer(() -> {
|
||||||
|
List<String> 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<String> 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);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -81,4 +81,22 @@ logging:
|
|||||||
level:
|
level:
|
||||||
org.springframework.cloud.gateway: DEBUG # 查看 Gateway 过滤器链
|
org.springframework.cloud.gateway: DEBUG # 查看 Gateway 过滤器链
|
||||||
org.springframework.security: DEBUG # 检查 Spring Security 拦截
|
org.springframework.security: DEBUG # 检查 Spring Security 拦截
|
||||||
reactor.netty.http.client: DEBUG # 查看网络层交互
|
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
|
||||||
@ -76,7 +76,7 @@ public class AdminMpAccountController {
|
|||||||
@PostMapping("/generate-qr-code")
|
@PostMapping("/generate-qr-code")
|
||||||
@Operation(summary = "生成公众号二维码")
|
@Operation(summary = "生成公众号二维码")
|
||||||
@SaCheckPermission("admin:mp:account:qr-code'")
|
@SaCheckPermission("admin:mp:account:qr-code'")
|
||||||
public ResultBean<Boolean> generateAccountQrCode(@RequestParam("id") Integer id) {
|
public ResultBean<Boolean> generateAccountQrCode(@RequestParam("id") Integer id,@RequestParam("场景值") String sceneStr) {
|
||||||
return ResultBean.success(mpAccountService.generateAccountQrCode(id));
|
return ResultBean.success(mpAccountService.generateAccountQrCode(id,sceneStr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,12 +141,12 @@ public class AdminMpAccountService {
|
|||||||
* @param id 公众号账号ID
|
* @param id 公众号账号ID
|
||||||
* @return 是否生成成功
|
* @return 是否生成成功
|
||||||
*/
|
*/
|
||||||
public Boolean generateAccountQrCode(Integer id) {
|
public Boolean generateAccountQrCode(Integer id,String sceneStr) {
|
||||||
MpAccountEntity account = mpAccountService.getById(id);
|
MpAccountEntity account = mpAccountService.getById(id);
|
||||||
WxMpService mpService = mpServiceFactory.getRequiredMpService(account.getAppId());
|
WxMpService mpService = mpServiceFactory.getRequiredMpService(account.getAppId());
|
||||||
String qrCodeUrl;
|
String qrCodeUrl;
|
||||||
try {
|
try {
|
||||||
WxMpQrCodeTicket qrCodeTicket = mpService.getQrcodeService().qrCodeCreateLastTicket("default");
|
WxMpQrCodeTicket qrCodeTicket = mpService.getQrcodeService().qrCodeCreateLastTicket(sceneStr);
|
||||||
qrCodeUrl = mpService.getQrcodeService().qrCodePictureUrl(qrCodeTicket.getTicket());
|
qrCodeUrl = mpService.getQrcodeService().qrCodePictureUrl(qrCodeTicket.getTicket());
|
||||||
} catch (WxErrorException e) {
|
} catch (WxErrorException e) {
|
||||||
log.error("生成公众号二维码失败", e);
|
log.error("生成公众号二维码失败", e);
|
||||||
|
|||||||
@ -7,7 +7,12 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class MpGenerateQrCodeReq {
|
public class MpGenerateQrCodeReq {
|
||||||
|
|
||||||
private String userId;
|
@Schema(description = "场景值")
|
||||||
|
private String sceneStr;
|
||||||
|
|
||||||
|
@Schema(description = "小程序appid")
|
||||||
private String appId;
|
private String appId;
|
||||||
}
|
|
||||||
|
@Schema(description = "二维码类型 1-临时 2-永久")
|
||||||
|
private Integer type;
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ import com.seer.teach.mp.factory.MpServiceFactory;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.chanjar.weixin.common.error.WxErrorException;
|
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.api.WxMpService;
|
||||||
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
|
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -30,8 +31,14 @@ public class AppOfficialQrCodeService {
|
|||||||
WxMpService wxMpService = mpServiceFactory.getRequiredMpService(req.getAppId());
|
WxMpService wxMpService = mpServiceFactory.getRequiredMpService(req.getAppId());
|
||||||
|
|
||||||
Integer expireSeconds = mpQrCodeExpireTime * 60 *60;
|
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());
|
String qrCodeUrl = wxMpService.getQrcodeService().qrCodePictureUrl(ticket.getTicket());
|
||||||
|
|
||||||
MpQrCodeResp resp = new MpQrCodeResp();
|
MpQrCodeResp resp = new MpQrCodeResp();
|
||||||
|
|||||||
@ -2,12 +2,12 @@ package com.seer.teach.teacher.common.req;
|
|||||||
|
|
||||||
import com.seer.teach.common.enums.teacher.ReportTypeEnum;
|
import com.seer.teach.common.enums.teacher.ReportTypeEnum;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
|||||||
@ -48,4 +48,8 @@ zs:
|
|||||||
decryption:
|
decryption:
|
||||||
enabled: false
|
enabled: false
|
||||||
encryption:
|
encryption:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
cors:
|
||||||
|
origins:
|
||||||
|
- http://10.10.3.134:8020
|
||||||
|
- http://10.10.4.143:8020
|
||||||
@ -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;
|
private String code;
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import com.seer.teach.common.annotation.EncryptionAnnotation;
|
|||||||
import com.seer.teach.common.annotation.LogOperation;
|
import com.seer.teach.common.annotation.LogOperation;
|
||||||
import com.seer.teach.common.annotation.LogPrint;
|
import com.seer.teach.common.annotation.LogPrint;
|
||||||
import com.seer.teach.common.enums.ModuleEnum;
|
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.response.LoginResp;
|
||||||
import com.seer.teach.user.app.auth.service.AppAuthService;
|
import com.seer.teach.user.app.auth.service.AppAuthService;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@ -37,7 +37,7 @@ public class AppAuthController {
|
|||||||
private AppAuthService userAuthService;
|
private AppAuthService userAuthService;
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResultBean<LoginResp> login(@RequestBody WeChatLoginParam request) {
|
public ResultBean<LoginResp> login(@RequestBody LoginParam request) {
|
||||||
return ResultBean.success(userAuthService.authenticate(request));
|
return ResultBean.success(userAuthService.authenticate(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,24 +2,24 @@ package com.seer.teach.user.app.auth.request;
|
|||||||
|
|
||||||
import com.seer.teach.user.app.auth.LoginType;
|
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 io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
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
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ToString
|
@ToString
|
||||||
@Builder
|
@Builder
|
||||||
@Schema(description = "微信登录请求实体类")
|
@Schema(description = "登录请求实体类")
|
||||||
public class WeChatLoginParam {
|
public class LoginParam {
|
||||||
|
|
||||||
|
@Schema(description = "登录方式不可为空")
|
||||||
|
@NotBlank(message = "loginType不可为空")
|
||||||
LoginType loginType;
|
LoginType loginType;
|
||||||
|
|
||||||
@Schema(description = "jsCode不可为空")
|
@Schema(description = "jsCode不可为空")
|
||||||
@ -5,7 +5,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
|||||||
import com.seer.teach.common.enums.ResultCodeEnum;
|
import com.seer.teach.common.enums.ResultCodeEnum;
|
||||||
import com.seer.teach.common.utils.AssertUtils;
|
import com.seer.teach.common.utils.AssertUtils;
|
||||||
import com.seer.teach.user.app.auth.LoginType;
|
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 com.seer.teach.user.app.auth.response.LoginResp;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -43,7 +43,7 @@ public class AppAuthService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class,timeout = 120)
|
@Transactional(rollbackFor = Exception.class,timeout = 120)
|
||||||
public LoginResp authenticate(WeChatLoginParam request) {
|
public LoginResp authenticate(LoginParam request) {
|
||||||
LoginStrategy strategy = strategyMap.get(request.getLoginType());
|
LoginStrategy strategy = strategyMap.get(request.getLoginType());
|
||||||
AssertUtils.notNull(strategy, ResultCodeEnum.LOGIN_TYPE_ERROR);
|
AssertUtils.notNull(strategy, ResultCodeEnum.LOGIN_TYPE_ERROR);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.seer.teach.user.app.auth.service;
|
package com.seer.teach.user.app.auth.service;
|
||||||
|
|
||||||
import com.seer.teach.user.app.auth.LoginType;
|
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 {
|
public interface LoginStrategy {
|
||||||
|
|
||||||
@ -13,5 +13,5 @@ public interface LoginStrategy {
|
|||||||
* @param request
|
* @param request
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
LoginUser authenticate(WeChatLoginParam request);
|
LoginUser authenticate(LoginParam request);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package com.seer.teach.user.app.auth.service;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class LoginUser {
|
public class LoginUser {
|
||||||
|
|
||||||
@ -17,6 +19,8 @@ public class LoginUser {
|
|||||||
*/
|
*/
|
||||||
private Integer applyStatus;
|
private Integer applyStatus;
|
||||||
|
|
||||||
|
private List<String> roles;
|
||||||
|
|
||||||
public LoginUser(Integer userId) {
|
public LoginUser(Integer userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import com.seer.teach.common.utils.AssertUtils;
|
|||||||
import com.seer.teach.mp.api.WechatMiniProgramApi;
|
import com.seer.teach.mp.api.WechatMiniProgramApi;
|
||||||
import com.seer.teach.mp.api.resp.WxMiniProgramSessionDTO;
|
import com.seer.teach.mp.api.resp.WxMiniProgramSessionDTO;
|
||||||
import com.seer.teach.user.app.auth.LoginType;
|
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.LoginStrategy;
|
||||||
import com.seer.teach.user.app.auth.service.LoginUser;
|
import com.seer.teach.user.app.auth.service.LoginUser;
|
||||||
import com.seer.teach.user.entity.UserAuthEntity;
|
import com.seer.teach.user.entity.UserAuthEntity;
|
||||||
@ -69,7 +69,7 @@ public class MiniProgramLoginStrategy extends AbstractLoginStrategy implements L
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginUser authenticate(WeChatLoginParam request) {
|
public LoginUser authenticate(LoginParam request) {
|
||||||
WxMiniProgramSessionDTO wxMiniProgramSessionDTO = wechatMiniProgramApi.code2Session(request.getJsCode());
|
WxMiniProgramSessionDTO wxMiniProgramSessionDTO = wechatMiniProgramApi.code2Session(request.getJsCode());
|
||||||
AssertUtils.isTrue(wxMiniProgramSessionDTO.isSuccess(), ResultCodeEnum.WX_OAUTH_USED_ERROR);
|
AssertUtils.isTrue(wxMiniProgramSessionDTO.isSuccess(), ResultCodeEnum.WX_OAUTH_USED_ERROR);
|
||||||
UserAuthEntity userAuth = userAuthService.getOneByOpenIdAndUnionId(wxMiniProgramSessionDTO.getOpenid(), wxMiniProgramSessionDTO.getUnionid());
|
UserAuthEntity userAuth = userAuthService.getOneByOpenIdAndUnionId(wxMiniProgramSessionDTO.getOpenid(), wxMiniProgramSessionDTO.getUnionid());
|
||||||
@ -156,7 +156,7 @@ public class MiniProgramLoginStrategy extends AbstractLoginStrategy implements L
|
|||||||
* @param request 登录参数
|
* @param request 登录参数
|
||||||
* @return boolean true 是扫码登录,false 密码登录
|
* @return boolean true 是扫码登录,false 密码登录
|
||||||
*/
|
*/
|
||||||
private boolean isScanQrCodeLogin(WeChatLoginParam request) {
|
private boolean isScanQrCodeLogin(LoginParam request) {
|
||||||
if (!StringUtils.hasText(request.getScene())) {
|
if (!StringUtils.hasText(request.getScene())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import com.seer.teach.common.utils.AssertUtils;
|
|||||||
import com.seer.teach.mp.api.WechatOfficialAccountApi;
|
import com.seer.teach.mp.api.WechatOfficialAccountApi;
|
||||||
import com.seer.teach.mp.api.resp.WxOAuth2AccessTokenDTO;
|
import com.seer.teach.mp.api.resp.WxOAuth2AccessTokenDTO;
|
||||||
import com.seer.teach.user.app.auth.LoginType;
|
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.LoginStrategy;
|
||||||
import com.seer.teach.user.app.auth.service.LoginUser;
|
import com.seer.teach.user.app.auth.service.LoginUser;
|
||||||
import com.seer.teach.user.entity.UserAuthEntity;
|
import com.seer.teach.user.entity.UserAuthEntity;
|
||||||
@ -28,7 +28,6 @@ public class OfficialAccountLoginStrategy extends AbstractLoginStrategy implemen
|
|||||||
@Autowired
|
@Autowired
|
||||||
private WechatOfficialAccountApi wechatOfficialAccountApi;
|
private WechatOfficialAccountApi wechatOfficialAccountApi;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IUserService userService;
|
private IUserService userService;
|
||||||
|
|
||||||
@ -41,7 +40,7 @@ public class OfficialAccountLoginStrategy extends AbstractLoginStrategy implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginUser authenticate(WeChatLoginParam request) {
|
public LoginUser authenticate(LoginParam request) {
|
||||||
log.info("微信公众号登录:{}",request);
|
log.info("微信公众号登录:{}",request);
|
||||||
WxOAuth2AccessTokenDTO wxOAuth2AccessToken = wechatOfficialAccountApi.getUserWxOAuth2AccessToken(request.getAppId(), request.getJsCode());
|
WxOAuth2AccessTokenDTO wxOAuth2AccessToken = wechatOfficialAccountApi.getUserWxOAuth2AccessToken(request.getAppId(), request.getJsCode());
|
||||||
log.debug("获取用户信息:{}",wxOAuth2AccessToken);
|
log.debug("获取用户信息:{}",wxOAuth2AccessToken);
|
||||||
@ -61,7 +60,8 @@ public class OfficialAccountLoginStrategy extends AbstractLoginStrategy implemen
|
|||||||
}else{
|
}else{
|
||||||
userAuth.setAppId(request.getAppId());
|
userAuth.setAppId(request.getAppId());
|
||||||
updateUserAuth(userAuth);
|
updateUserAuth(userAuth);
|
||||||
|
LoginUser loginUser = new LoginUser(userAuth.getUserId());
|
||||||
|
return loginUser;
|
||||||
}
|
}
|
||||||
return new LoginUser(userAuth.getUserId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ import com.seer.teach.common.utils.CommonUtils;
|
|||||||
import com.seer.teach.mp.api.WechatOfficialAccountApi;
|
import com.seer.teach.mp.api.WechatOfficialAccountApi;
|
||||||
import com.seer.teach.mp.api.resp.WxOAuth2AccessTokenDTO;
|
import com.seer.teach.mp.api.resp.WxOAuth2AccessTokenDTO;
|
||||||
import com.seer.teach.user.app.auth.LoginType;
|
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.LoginStrategy;
|
||||||
import com.seer.teach.user.app.auth.service.LoginUser;
|
import com.seer.teach.user.app.auth.service.LoginUser;
|
||||||
import com.seer.teach.user.entity.RoleEntity;
|
import com.seer.teach.user.entity.RoleEntity;
|
||||||
@ -52,7 +52,7 @@ public class WarehouseAccountLoginStrategy extends AbstractLoginStrategy impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginUser authenticate(WeChatLoginParam request) {
|
public LoginUser authenticate(LoginParam request) {
|
||||||
AssertUtils.notNull(request.getPassword(), ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR);
|
AssertUtils.notNull(request.getPassword(), ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR);
|
||||||
UserEntity accountUser = userService.getOneByUserName(request.getUserName());
|
UserEntity accountUser = userService.getOneByUserName(request.getUserName());
|
||||||
AssertUtils.notNull(accountUser, ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR);
|
AssertUtils.notNull(accountUser, ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR);
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import com.seer.teach.iot.api.UserDeviceServiceApi;
|
|||||||
import com.seer.teach.mp.api.WechatMiniProgramApi;
|
import com.seer.teach.mp.api.WechatMiniProgramApi;
|
||||||
import com.seer.teach.mp.api.resp.WxMiniProgramSessionDTO;
|
import com.seer.teach.mp.api.resp.WxMiniProgramSessionDTO;
|
||||||
import com.seer.teach.user.app.auth.LoginType;
|
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.LoginStrategy;
|
||||||
import com.seer.teach.user.app.auth.service.LoginUser;
|
import com.seer.teach.user.app.auth.service.LoginUser;
|
||||||
import com.seer.teach.user.entity.UserAuthEntity;
|
import com.seer.teach.user.entity.UserAuthEntity;
|
||||||
@ -49,7 +49,7 @@ public class WechatChildrenAccountLoginStrategy extends AbstractLoginStrategy im
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginUser authenticate(WeChatLoginParam request) {
|
public LoginUser authenticate(LoginParam request) {
|
||||||
UserEntity accountUser =userService.getOneByMobile(request.getPhoneNumber());
|
UserEntity accountUser =userService.getOneByMobile(request.getPhoneNumber());
|
||||||
AssertUtils.notNull(accountUser, ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR);
|
AssertUtils.notNull(accountUser, ResultCodeEnum.USERNAME_OR_PASSWORD_IS_ERROR);
|
||||||
String password = CommonUtils.encryptPassword(request.getPassword());
|
String password = CommonUtils.encryptPassword(request.getPassword());
|
||||||
|
|||||||
@ -55,4 +55,6 @@ public class AppUserInfoResp {
|
|||||||
|
|
||||||
@Schema(description = "是否是主监护人")
|
@Schema(description = "是否是主监护人")
|
||||||
private boolean isPrimaryGuardian;
|
private boolean isPrimaryGuardian;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -18,8 +18,21 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public interface IUserRoleService extends IService<UserRoleEntity> {
|
public interface IUserRoleService extends IService<UserRoleEntity> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID获取用户角色列表
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 用户角色列表
|
||||||
|
*/
|
||||||
List<UserRoleEntity> getListByUserId(Integer userId);
|
List<UserRoleEntity> getListByUserId(Integer userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户角色编码列表
|
||||||
|
*
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @return 角色编码列表
|
||||||
|
*/
|
||||||
|
List<String> getRoleCodeListByUserId(Integer userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 为用户分配角色
|
* 为用户分配角色
|
||||||
|
|||||||
@ -44,6 +44,19 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRoleEnt
|
|||||||
return list(new LambdaQueryWrapper<>(UserRoleEntity.class).eq(UserRoleEntity::getUserId, userId));
|
return list(new LambdaQueryWrapper<>(UserRoleEntity.class).eq(UserRoleEntity::getUserId, userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getRoleCodeListByUserId(Integer userId) {
|
||||||
|
List<UserRoleEntity> userRoleList = this.getListByUserId(userId);
|
||||||
|
if(CollectionUtil.isNotEmpty(userRoleList)){
|
||||||
|
List<Integer> roleIds = userRoleList.stream().map(UserRoleEntity::getRoleId).collect(Collectors.toList());
|
||||||
|
if(CollectionUtil.isNotEmpty(roleIds)){
|
||||||
|
Collection<RoleEntity> roles = roleService.getRoleListByRoleIds(roleIds);
|
||||||
|
return roles.stream().map(RoleEntity::getRoleCode).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void assignUserRole(Integer userId, Set<Integer> roleIds) {
|
public void assignUserRole(Integer userId, Set<Integer> roleIds) {
|
||||||
List<UserRoleEntity> userRoleList = this.getListByUserId(userId);
|
List<UserRoleEntity> userRoleList = this.getListByUserId(userId);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user