yshop-pro init

This commit is contained in:
hupeng
2023-05-19 18:29:26 +08:00
commit 6ff21a3799
1846 changed files with 114288 additions and 0 deletions

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>co.yixiang.boot</groupId>
<artifactId>yshop-framework</artifactId>
<version>${revision}</version>
</parent>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
<artifactId>yshop-spring-boot-starter-biz-social</artifactId>
<name>${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>co.yixiang.boot</groupId>
<artifactId>yshop-common</artifactId>
</dependency>
<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>co.yixiang.boot</groupId>
<artifactId>yshop-spring-boot-starter-web</artifactId>
</dependency>
<!-- spring boot 配置所需依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.xkcoding.justauth</groupId>
<artifactId>justauth-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>co.yixiang.boot</groupId>
<artifactId>yshop-spring-boot-starter-redis</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,36 @@
package co.yixiang.yshop.framework.social.config;
import co.yixiang.yshop.framework.social.core.YshopAuthRequestFactory;
import com.xkcoding.http.HttpUtil;
import com.xkcoding.http.support.hutool.HutoolImpl;
import com.xkcoding.justauth.autoconfigure.JustAuthProperties;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.cache.AuthStateCache;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
/**
* 社交自动装配类
*
* @author timfruit
* @date 2021-10-30
*/
@Slf4j
@AutoConfiguration
@EnableConfigurationProperties(JustAuthProperties.class)
public class YshopSocialAutoConfiguration {
@Bean
@Primary
@ConditionalOnProperty(prefix = "justauth", value = "enabled", havingValue = "true", matchIfMissing = true)
public YshopAuthRequestFactory yshopAuthRequestFactory(JustAuthProperties properties, AuthStateCache authStateCache) {
// 需要修改 HttpUtil 使用的实现,避免类报错
HttpUtil.setHttp(new HutoolImpl());
// 创建 YshopAuthRequestFactory
return new YshopAuthRequestFactory(properties, authStateCache);
}
}

View File

@ -0,0 +1,85 @@
package co.yixiang.yshop.framework.social.core;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ReflectUtil;
import co.yixiang.yshop.framework.social.core.enums.AuthExtendSource;
import co.yixiang.yshop.framework.social.core.request.AuthWeChatMiniAppRequest;
import com.xkcoding.justauth.AuthRequestFactory;
import com.xkcoding.justauth.autoconfigure.JustAuthProperties;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.request.AuthRequest;
import java.lang.reflect.Method;
/**
* 第三方授权拓展 request 工厂类
* 为使得拓展配置 {@link AuthConfig} 和默认配置齐平,所以自定义本工厂类
*
* @author timfruit
* @date 2021-10-31
*/
public class YshopAuthRequestFactory extends AuthRequestFactory {
protected JustAuthProperties properties;
protected AuthStateCache authStateCache;
/**
* 由于父类 configureHttpConfig 方法是 private 修饰,所以获取后,进行反射调用
*/
private final Method configureHttpConfigMethod = ReflectUtil.getMethod(AuthRequestFactory.class,
"configureHttpConfig", String.class, AuthConfig.class, JustAuthProperties.JustAuthHttpConfig.class);
public YshopAuthRequestFactory(JustAuthProperties properties, AuthStateCache authStateCache) {
super(properties, authStateCache);
this.properties = properties;
this.authStateCache = authStateCache;
}
/**
* 返回 AuthRequest 对象
*
* @param source {@link AuthSource}
* @return {@link AuthRequest}
*/
@Override
public AuthRequest get(String source) {
// 先尝试获取自定义扩展的
AuthRequest authRequest = getExtendRequest(source);
// 找不到,使用默认拓展
if (authRequest == null) {
authRequest = super.get(source);
}
return authRequest;
}
protected AuthRequest getExtendRequest(String source) {
AuthExtendSource authExtendSource;
try {
authExtendSource = EnumUtil.fromString(AuthExtendSource.class, source.toUpperCase());
} catch (IllegalArgumentException e) {
// 无自定义匹配
return null;
}
// 拓展配置和默认配置齐平properties 放在一起
AuthConfig config = properties.getType().get(authExtendSource.name());
// 找不到对应关系,直接返回空
if (config == null) {
return null;
}
// 反射调用,配置 http config
ReflectUtil.invoke(this, configureHttpConfigMethod, authExtendSource.name(), config, properties.getHttpConfig());
// 获得拓展的 Request
// noinspection SwitchStatementWithTooFewBranches
switch (authExtendSource) {
case WECHAT_MINI_APP:
return new AuthWeChatMiniAppRequest(config, authStateCache);
default:
return null;
}
}
}

View File

@ -0,0 +1,39 @@
package co.yixiang.yshop.framework.social.core.enums;
import me.zhyd.oauth.config.AuthSource;
/**
* 拓展 JustAuth 各 api 需要的 url 用枚举类分平台类型管理
*
* 默认配置 {@link me.zhyd.oauth.config.AuthDefaultSource}
*
* @author timfruit
*/
public enum AuthExtendSource implements AuthSource {
/**
* 微信小程序授权登录
*/
WECHAT_MINI_APP {
@Override
public String authorize() {
// 参见 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 文档
throw new UnsupportedOperationException("不支持获取授权 url请使用小程序内置函数 wx.login() 登录获取 code");
}
@Override
public String accessToken() {
// 参见 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html 文档
// 获取 openid, unionId , session_key 等字段
return "https://api.weixin.qq.com/sns/jscode2session";
}
@Override
public String userInfo() {
// 参见 https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html 文档
throw new UnsupportedOperationException("不支持获取用户信息 url请使用小程序内置函数 wx.getUserProfile() 获取用户信息");
}
}
}

View File

@ -0,0 +1,97 @@
package co.yixiang.yshop.framework.social.core.request;
import co.yixiang.yshop.framework.common.util.json.JsonUtils;
import co.yixiang.yshop.framework.social.core.enums.AuthExtendSource;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthDefaultRequest;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* 微信小程序登陆 Request 请求
*
* 由于 JustAuth 定位是面向 Web 为主的三方登录,所以微信小程序只能自己封装
*
* @author timfruit
* @date 2021-10-29
*/
public class AuthWeChatMiniAppRequest extends AuthDefaultRequest {
public AuthWeChatMiniAppRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthExtendSource.WECHAT_MINI_APP, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
// 参见 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html 文档
// 使用 code 获取对应的 openId、unionId 等字段
String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(authCallback.getCode()));
JSCode2SessionResponse accessTokenObject = JsonUtils.parseObject(response, JSCode2SessionResponse.class);
assert accessTokenObject != null;
checkResponse(accessTokenObject);
// 拼装结果
return AuthToken.builder()
.openId(accessTokenObject.getOpenid())
.unionId(accessTokenObject.getUnionId())
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
// 参见 https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html 文档
// 如果需要用户信息,需要在小程序调用函数后传给后端
return AuthUser.builder()
.username("")
.nickname("")
.avatar("")
.uuid(authToken.getOpenId())
.token(authToken)
.source(source.toString())
.build();
}
/**
* 检查响应内容是否正确
*
* @param response 请求响应内容
*/
private void checkResponse(JSCode2SessionResponse response) {
if (response.getErrorCode() != 0) {
throw new AuthException(response.getErrorCode(), response.getErrorMsg());
}
}
@Override
protected String accessTokenUrl(String code) {
return UrlBuilder.fromBaseUrl(source.accessToken())
.queryParam("appid", config.getClientId())
.queryParam("secret", config.getClientSecret())
.queryParam("js_code", code) // 和父类不同,所以需要重写该方法
.queryParam("grant_type", "authorization_code")
.build();
}
@Data
@SuppressWarnings("SpellCheckingInspection")
private static class JSCode2SessionResponse {
@JsonProperty("errcode")
private int errorCode;
@JsonProperty("errmsg")
private String errorMsg;
@JsonProperty("session_key")
private String sessionKey;
private String openid;
@JsonProperty("unionid")
private String unionId;
}
}

View File

@ -0,0 +1 @@
co.yixiang.yshop.framework.social.config.YshopSocialAutoConfiguration