MEMBER:同步 jdk21 boot 最新代码

This commit is contained in:
YunaiV 2024-01-19 21:19:48 +08:00
parent 8289a22f03
commit 2208eef8cf
23 changed files with 284 additions and 27 deletions

View File

@ -10,7 +10,7 @@ import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
/**
* 时间工具类用于 {@link LocalDateTime}
* 时间工具类用于 {@link java.time.LocalDateTime}
*
* @author 芋道源码
*/

View File

@ -10,7 +10,7 @@ import java.util.function.Consumer;
/**
* Bean 工具类
*
* 1. 默认使用 {@link BeanUtil} 作为实现类虽然不同 bean 工具的性能有差别但是对绝大多数同学的项目不用在意这点性能
* 1. 默认使用 {@link cn.hutool.core.bean.BeanUtil} 作为实现类虽然不同 bean 工具的性能有差别但是对绝大多数同学的项目不用在意这点性能
* 2. 针对复杂的对象转换可以搜参考 AuthConvert 实现通过 mapstruct + default 配合实现
*
* @author 芋道源码

View File

@ -12,7 +12,7 @@ import org.springframework.util.Assert;
import static java.util.Collections.singletonList;
/**
* {@link PageParam} 工具类
* {@link cn.iocoder.yudao.framework.common.pojo.PageParam} 工具类
*
* @author 芋道源码
*/

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.flowable.config;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.flowable.core.web.FlowableWebFilter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.AsyncListenableTaskExecutor;
@ -16,7 +17,8 @@ public class YudaoFlowableConfiguration {
*
* 如果不创建会导致项目启动时Flowable 报错的问题
*/
@Bean
@Bean(name = "applicationTaskExecutor")
@ConditionalOnMissingBean(name = "applicationTaskExecutor")
public AsyncListenableTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
@ -40,4 +42,5 @@ public class YudaoFlowableConfiguration {
registrationBean.setOrder(WebFilterOrderEnum.FLOWABLE_FILTER);
return registrationBean;
}
}

View File

@ -1,9 +1,12 @@
package cn.iocoder.yudao.framework.web.core.util;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@ -26,6 +29,13 @@ public class WebFrameworkUtils {
public static final String HEADER_TENANT_ID = "tenant-id";
/**
* 终端的 Header
*
* @see cn.iocoder.yudao.framework.common.enums.TerminalEnum
*/
public static final String HEADER_TERMINAL = "terminal";
private static WebProperties properties;
public WebFrameworkUtils(WebProperties webProperties) {
@ -108,6 +118,15 @@ public class WebFrameworkUtils {
return getLoginUserId(request);
}
public static Integer getTerminal() {
HttpServletRequest request = getRequest();
if (request == null) {
return TerminalEnum.UNKNOWN.getTerminal();
}
String terminalValue = request.getHeader(HEADER_TERMINAL);
return NumberUtil.parseInt(terminalValue, TerminalEnum.UNKNOWN.getTerminal());
}
public static void setCommonResult(ServletRequest request, CommonResult<?> result) {
request.setAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT, result);
}

View File

@ -10,8 +10,7 @@ import java.util.Map;
@Data
public class FileConfigSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "编号不能为空")
@Schema(description = "编号", example = "1")
private Long id;
@Schema(description = "配置名", requiredMode = Schema.RequiredMode.REQUIRED, example = "S3 - 阿里云")

View File

@ -18,7 +18,7 @@ public interface ErrorCodeConstants {
// ========== AUTH 模块 1-004-003-000 ==========
ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_004_003_000, "登录失败,账号密码不正确");
ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_004_003_001, "登录失败,账号被禁用");
ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_004_003_005, "未绑定账号,需要进行绑定");
ErrorCode AUTH_SOCIAL_USER_NOT_FOUND = new ErrorCode(1_004_003_005, "登录失败,解析不到三方登录信息");
ErrorCode AUTH_MOBILE_USED = new ErrorCode(1_004_003_007, "手机号已经被使用");
// ========== 用户收件地址 1-004-004-000 ==========

View File

@ -121,7 +121,7 @@ public class AppAuthController {
description = "参考 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html 文档")
public CommonResult<SocialWxJsapiSignatureRespDTO> createWeixinMpJsapiSignature(@RequestParam("url") String url) {
SocialWxJsapiSignatureRespDTO signature = socialClientApi.createWxMpJsapiSignature(
UserTypeEnum.MEMBER.getValue(), url);
UserTypeEnum.MEMBER.getValue(), url).getCheckedData();
return success(AuthConvert.INSTANCE.convert(signature));
}

View File

@ -37,7 +37,7 @@ public class AppSocialUserController {
public CommonResult<String> socialBind(@RequestBody @Valid AppSocialUserBindReqVO reqVO) {
SocialUserBindReqDTO reqDTO = new SocialUserBindReqDTO(getLoginUserId(), UserTypeEnum.MEMBER.getValue(),
reqVO.getType(), reqVO.getCode(), reqVO.getState());
String openid = socialUserApi.bindSocialUser(reqDTO);
String openid = socialUserApi.bindSocialUser(reqDTO).getCheckedData();
return success(openid);
}
@ -47,7 +47,7 @@ public class AppSocialUserController {
public CommonResult<Boolean> socialUnbind(@RequestBody AppSocialUserUnbindReqVO reqVO) {
SocialUserUnbindReqDTO reqDTO = new SocialUserUnbindReqDTO(getLoginUserId(), UserTypeEnum.MEMBER.getValue(),
reqVO.getType(), reqVO.getOpenid());
socialUserApi.unbindSocialUser(reqDTO);
socialUserApi.unbindSocialUser(reqDTO).getCheckedData();
return success(true);
}
@ -56,7 +56,7 @@ public class AppSocialUserController {
@Parameter(name = "type", description = "社交平台的类型,参见 SocialTypeEnum 枚举值", required = true, example = "10")
@PreAuthenticated
public CommonResult<AppSocialUserRespVO> getSocialUser(@RequestParam("type") Integer type) {
SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(UserTypeEnum.MEMBER.getValue(), getLoginUserId(), type);
SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(UserTypeEnum.MEMBER.getValue(), getLoginUserId(), type).getCheckedData();
return success(BeanUtils.toBean(socialUser, AppSocialUserRespVO.class));
}

View File

@ -70,7 +70,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
String openid = null;
if (reqVO.getSocialType() != null) {
openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())).getCheckedData();
}
// 创建 Token 令牌记录登录日志
@ -92,7 +92,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
String openid = null;
if (reqVO.getSocialType() != null) {
openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())).getCheckedData();
}
// 创建 Token 令牌记录登录日志
@ -104,7 +104,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) {
// 使用 code 授权码进行登录然后获得到绑定的用户编号
SocialUserRespDTO socialUser = socialUserApi.getSocialUserByCode(UserTypeEnum.MEMBER.getValue(), reqVO.getType(),
reqVO.getCode(), reqVO.getState());
reqVO.getCode(), reqVO.getState()).getCheckedData();
if (socialUser == null) {
throw exception(AUTH_SOCIAL_USER_NOT_FOUND);
}
@ -131,7 +131,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
public AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO) {
// 获得对应的手机号信息
SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo(
UserTypeEnum.MEMBER.getValue(), reqVO.getPhoneCode());
UserTypeEnum.MEMBER.getValue(), reqVO.getPhoneCode()).getCheckedData();
Assert.notNull(phoneNumberInfo, "获得手机信息失败,结果为空");
// 获得获得注册用户
@ -141,7 +141,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
// 绑定社交用户
String openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), reqVO.getState()));
SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), reqVO.getState())).getCheckedData();
// 创建 Token 令牌记录登录日志
return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, openid);
@ -154,14 +154,14 @@ public class MemberAuthServiceImpl implements MemberAuthService {
// 创建 Token 令牌
OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
.setUserId(user.getId()).setUserType(getUserType().getValue())
.setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
.setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT)).getCheckedData();
// 构建返回结果
return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid);
}
@Override
public String getSocialAuthorizeUrl(Integer type, String redirectUri) {
return socialClientApi.getAuthorizeUrl(type, UserTypeEnum.MEMBER.getValue(), redirectUri);
return socialClientApi.getAuthorizeUrl(type, UserTypeEnum.MEMBER.getValue(), redirectUri).getCheckedData();
}
private MemberUserDO login0(String mobile, String password) {
@ -205,7 +205,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Override
public void logout(String token) {
// 删除访问令牌
OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.removeAccessToken(token);
OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.removeAccessToken(token).getCheckedData();
if (accessTokenRespDTO == null) {
return;
}
@ -248,7 +248,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Override
public AppAuthLoginRespVO refreshToken(String refreshToken) {
OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken,
OAuth2ClientConstants.CLIENT_ID_DEFAULT);
OAuth2ClientConstants.CLIENT_ID_DEFAULT).getCheckedData();
return AuthConvert.INSTANCE.convert(accessTokenDO, null);
}

View File

@ -172,7 +172,7 @@ public class MemberUserServiceImpl implements MemberUserService {
public void updateUserMobileByWeixin(Long userId, AppMemberUserUpdateMobileByWeixinReqVO reqVO) {
// 1.1 获得对应的手机号信息
SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo(
UserTypeEnum.MEMBER.getValue(), reqVO.getCode());
UserTypeEnum.MEMBER.getValue(), reqVO.getCode()).getCheckedData();
Assert.notNull(phoneNumberInfo, "获得手机信息失败,结果为空");
// 1.2 校验新手机是否已经被绑定
validateMobileUnique(userId, phoneNumberInfo.getPhoneNumber());

View File

@ -9,7 +9,11 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
*/
public interface ErrorCodeConstants {
// ========== AUTH 模块 1-003-000-000 ==========
// ========== GoView 模块 1-003-000-000 ==========
ErrorCode GO_VIEW_PROJECT_NOT_EXISTS = new ErrorCode(1_003_000_000, "GoView 项目不存在");
// ========== UREPORT 模块 1-003-001-000 ==========
ErrorCode UREPORT_DATA_NOT_EXISTS = new ErrorCode(1_003_001_001, "Ureport2 报表不存在");
ErrorCode UREPORT_DATABASE_NOT_EXISTS = new ErrorCode(1_003_001_002, "Ureport2 报表数据源不存在");
}

View File

@ -1 +1,2 @@
DELETE FROM "report_go_view_project";
DELETE FROM "report_ureport_data";

View File

@ -12,3 +12,16 @@ CREATE TABLE IF NOT EXISTS "report_go_view_project" (
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT 'GoView 项目表';
CREATE TABLE IF NOT EXISTS "report_ureport_data" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar NOT NULL,
"status" int NOT NULL,
"content" varchar,
"remark" varchar,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT 'Ureport2报表';

View File

@ -4,13 +4,17 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.NoArgsConstructor;
@Schema(description = "RPC 服务 - 取消绑定社交用户 Request DTO")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SocialUserUnbindReqDTO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")

View File

@ -0,0 +1,50 @@
package cn.iocoder.yudao.module.system.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.mzt.logapi.service.IParseFunction;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 管理员名字的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Slf4j
@Component
public class AdminUserParseFunction implements IParseFunction {
public static final String NAME = "getAdminUserById";
@Resource
private AdminUserApi adminUserApi;
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
// 获取用户信息
AdminUserRespDTO user = adminUserApi.getUser(Long.parseLong(value.toString())).getCheckedData();
if (user == null) {
log.warn("[apply][获取用户{{}}为空", value);
return "";
}
// 返回格式 芋道源码(13888888888)
String nickname = user.getNickname();
if (StrUtil.isEmpty(user.getMobile())) {
return nickname;
}
return StrUtil.format("{}({})", nickname, user.getMobile());
}
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.system.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 地名的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Slf4j
@Component
public class AreaParseFunction implements IParseFunction {
public static final String NAME = "getArea";
@Override
public boolean executeBefore() {
return true; // 先转换值后对比
}
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
return AreaUtils.format(Integer.parseInt(value.toString()));
}
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.module.infra.enums.DictTypeConstants;
import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 是否类型的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Component
@Slf4j
public class BooleanParseFunction implements IParseFunction {
public static final String NAME = "getBoolean";
@Override
public boolean executeBefore() {
return true; // 先转换值后对比
}
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BOOLEAN_STRING, value.toString());
}
}

View File

@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.system.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import com.mzt.logapi.service.IParseFunction;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 管理员名字的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Slf4j
@Component
public class DeptParseFunction implements IParseFunction {
public static final String NAME = "getDeptById";
@Resource
private DeptApi deptApi;
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
// 获取部门信息
DeptRespDTO dept = deptApi.getDept(Long.parseLong(value.toString())).getCheckedData();
if (dept == null) {
log.warn("[apply][获取部门{{}}为空", value);
return "";
}
return dept.getName();
}
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.framework.operatelog.core;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 行业的 {@link IParseFunction} 实现类
*
* @author HUIHUI
*/
@Component
@Slf4j
public class SexParseFunction implements IParseFunction {
public static final String NAME = "getSex";
@Override
public boolean executeBefore() {
return true; // 先转换值后对比
}
@Override
public String functionName() {
return NAME;
}
@Override
public String apply(Object value) {
if (StrUtil.isEmptyIfStr(value)) {
return "";
}
return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.USER_SEX, value.toString());
}
}

View File

@ -0,0 +1 @@
package cn.iocoder.yudao.module.system.framework.operatelog;

View File

@ -168,7 +168,6 @@ justauth:
client-secret: ${wx.mp.secret}
ignore-check-redirect-uri: true
ignore-check-state: true # 微信公众号,未调用后端的 getSocialAuthorizeUrl 方法,所以无法进行 state 校验 TODO 芋艿:后续考虑支持
cache:
type: REDIS
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::

View File

@ -131,20 +131,24 @@ logging:
--- #################### 微信公众号、小程序相关配置 ####################
wx:
mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档
# app-id: wx041349c6f39b268b
# app-id: wx041349c6f39b268b # 测试号(牛希尧提供的)
# secret: 5abee519483bc9f8cb37ce280e814bd0
app-id: wx5b23ba7a5589ecbb # 测试号
app-id: wx5b23ba7a5589ecbb # 测试号(自己的)
secret: 2a7b3b20c537e52e74afd395eb85f61f
# app-id: wxa69ab825b163be19 # 测试号Kongdy 提供的)
# secret: bd4f9fab889591b62aeac0d7b8d8b4a0
# 存储配置,解决 AccessToken 的跨节点的共享
config-storage:
type: RedisTemplate # 采用 RedisTemplate 操作 Redis会自动从 Spring 中获取
key-prefix: wx # Redis Key 的前缀
http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档
# appid: wx62056c0d5e8db250
# appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的)
# secret: 333ae72f41552af1e998fe1f54e1584a
appid: wx63c280fe3248a3e7 # wenhualian的接口测试号
secret: 6f270509224a7ae1296bbf1c8cb97aed
# appid: wxc4598c446f8a9cb3 # 测试号Kongdy 提供的)
# secret: 4a1a04e07f6a4a0751b39c3064a92c8b
config-storage:
type: RedisTemplate # 采用 RedisTemplate 操作 Redis会自动从 Spring 中获取
key-prefix: wa # Redis Key 的前缀
@ -197,7 +201,6 @@ justauth:
client-secret: ${wx.mp.secret}
ignore-check-redirect-uri: true
ignore-check-state: true # 微信公众号,未调用后端的 getSocialAuthorizeUrl 方法,所以无法进行 state 校验 TODO 芋艿:后续考虑支持
cache:
type: REDIS
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::