第三方登录集成unionID

This commit is contained in:
pikachu1995@126.com 2023-03-02 10:45:43 +08:00
parent 74972eaa37
commit 8d8cffca71
18 changed files with 323 additions and 266 deletions

View File

@ -47,7 +47,7 @@ public class ConnectBuyerWebController {
@GetMapping("/login/web/{type}") @GetMapping("/login/web/{type}")
@ApiOperation(value = "WEB信任登录授权") @ApiOperation(value = "WEB信任登录授权,包含PC、WAP")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "type", value = "登录方式:QQ,微信,微信_PC", @ApiImplicitParam(name = "type", value = "登录方式:QQ,微信,微信_PC",
allowableValues = "QQ,WECHAT,WECHAT_PC", paramType = "path") allowableValues = "QQ,WECHAT,WECHAT_PC", paramType = "path")
@ -75,12 +75,12 @@ public class ConnectBuyerWebController {
return connectUtil.getResult(state); return connectUtil.getResult(state);
} }
@GetMapping("/register/auto") // @GetMapping("/register/auto")
@ApiOperation(value = "WEB信任登录授权") // @ApiOperation(value = "WEB信任登录授权")
public ResultMessage<Token> webAuthorize() { // public ResultMessage<Token> webAuthorize() {
Token token = memberService.autoRegister(); // Token token = memberService.autoRegister();
return ResultUtil.data(token); // return ResultUtil.data(token);
} // }
@ApiOperation(value = "unionID登录") @ApiOperation(value = "unionID登录")
@ApiImplicitParams({ @ApiImplicitParams({
@ -92,7 +92,7 @@ public class ConnectBuyerWebController {
@GetMapping("/app/login") @GetMapping("/app/login")
public ResultMessage<Token> unionLogin(ConnectAuthUser authUser, @RequestHeader("uuid") String uuid) { public ResultMessage<Token> unionLogin(ConnectAuthUser authUser, @RequestHeader("uuid") String uuid) {
try { try {
return ResultUtil.data(connectService.appLoginCallback(authUser, uuid)); return ResultUtil.data(connectService.unionLoginCallback(authUser, uuid));
} catch (Exception e) { } catch (Exception e) {
log.error("unionID登录错误", e); log.error("unionID登录错误", e);
} }

View File

@ -24,13 +24,13 @@ spring:
boot: boot:
admin: admin:
client: client:
url: http://192.168.0.116:8000 url: http://192.168.0.108:8000
cache: cache:
type: redis type: redis
# Redis # Redis
redis: redis:
host: 127.0.0.1 host: 192.168.0.108
port: 6379 port: 30379
password: lilishop password: lilishop
lettuce: lettuce:
pool: pool:
@ -60,7 +60,7 @@ spring:
default-datasource: default-datasource:
type: com.alibaba.druid.pool.DruidDataSource type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/lilishop?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai url: jdbc:mysql://192.168.0.108:30306/kuaidi100?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: root username: root
password: lilishop password: lilishop
maxActive: 50 maxActive: 50
@ -241,16 +241,16 @@ lili:
sk: zhNKVrJK6UPOhqIjn8AQvG37b9sz6 sk: zhNKVrJK6UPOhqIjn8AQvG37b9sz6
#域名 #域名
domain: domain:
pc: http://192.168.0.116:8888 pc: http://192.168.0.108:8888
wap: http://192.168.0.116:8888 wap: http://192.168.0.108:8888
seller: http://192.168.0.116:8888 seller: http://192.168.0.108:8888
admin: http://192.168.0.116:8888 admin: http://192.168.0.108:8888
#api地址 #api地址
api: api:
buyer: https://z171l91606.51mypc.cn buyer: https://z171l91606.51mypc.cn
base: http://192.168.0.116:8888 base: http://192.168.0.108:8888
manager: http://192.168.0.116:8888 manager: http://192.168.0.108:8888
seller: http://192.168.0.116:8888 seller: http://192.168.0.108:8888
# jwt 细节设定 # jwt 细节设定
jwt-setting: jwt-setting:
@ -269,7 +269,7 @@ lili:
data: data:
elasticsearch: elasticsearch:
cluster-name: elasticsearch cluster-name: elasticsearch
cluster-nodes: 127.0.0.1:9200 cluster-nodes: 192.168.0.108:30920
index: index:
number-of-replicas: 0 number-of-replicas: 0
number-of-shards: 3 number-of-shards: 3
@ -301,7 +301,7 @@ lili:
after-sale-topic: lili_after_sale_topic after-sale-topic: lili_after_sale_topic
after-sale-group: lili_after_sale_group after-sale-group: lili_after_sale_group
rocketmq: rocketmq:
name-server: 127.0.0.1:9876 name-server: 192.168.0.108:30876
isVIPChannel: false isVIPChannel: false
producer: producer:
group: lili_group group: lili_group
@ -310,7 +310,7 @@ rocketmq:
xxl: xxl:
job: job:
admin: admin:
addresses: http://127.0.0.1:9001/xxl-job-admin addresses: http://192.168.0.108:9001/xxl-job-admin
executor: executor:
appname: xxl-job-executor-lilishop appname: xxl-job-executor-lilishop
address: address:

View File

@ -0,0 +1,21 @@
package cn.lili.event;
import cn.lili.modules.connect.entity.dto.ConnectAuthUser;
import cn.lili.modules.member.entity.dos.Member;
/**
* 会员联合登录消息
*
* @author Chopper
* @since 2020/11/17 7:13 下午
*/
public interface MemberConnectLoginEvent {
/**
* 会员联合登录
*
* @param member 会员
* @param authUser 第三方登录
*/
void memberConnectLogin(Member member, ConnectAuthUser authUser);
}

View File

@ -1,25 +1,49 @@
package cn.lili.event.impl; package cn.lili.event.impl;
import cn.hutool.core.util.StrUtil;
import cn.lili.event.MemberConnectLoginEvent;
import cn.lili.event.MemberLoginEvent; import cn.lili.event.MemberLoginEvent;
import cn.lili.modules.connect.entity.dto.ConnectAuthUser;
import cn.lili.modules.connect.service.ConnectService;
import cn.lili.modules.member.entity.dos.Member; import cn.lili.modules.member.entity.dos.Member;
import cn.lili.modules.member.service.MemberService; import cn.lili.modules.member.service.MemberService;
import cn.lili.modules.system.service.SettingService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
* 会员自身业务 * 会员自身业务
* 会员登录会员第三方登录
* *
* @author Chopper * @author Chopper
* @version v1.0 * @version v1.0
* 2022-01-11 11:08 * 2022-01-11 11:08
*/ */
@Service @Service
public class MemberExecute implements MemberLoginEvent { public class MemberExecute implements MemberLoginEvent, MemberConnectLoginEvent {
@Autowired @Autowired
private MemberService memberService; private MemberService memberService;
@Autowired
private ConnectService connectService;
@Autowired
private SettingService settingService;
@Override @Override
public void memberLogin(Member member) { public void memberLogin(Member member) {
memberService.updateMemberLoginTime(member.getId()); memberService.updateMemberLoginTime(member.getId());
} }
@Override
public void memberConnectLogin(Member member, ConnectAuthUser authUser) {
//保存UnionID
if (StrUtil.isNotBlank(authUser.getToken().getUnionId())) {
connectService.loginBindUser(member.getId(), authUser.getToken().getUnionId(), authUser.getType());
}
//保存OpenID
if (StrUtil.isNotBlank(authUser.getUuid())) {
connectService.loginBindUser(member.getId(), authUser.getUuid(), authUser.getType());
}
}
} }

View File

@ -3,6 +3,7 @@ package cn.lili.listener;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.lili.event.*; import cn.lili.event.*;
import cn.lili.event.impl.ImTalkExecute; import cn.lili.event.impl.ImTalkExecute;
import cn.lili.modules.connect.entity.dto.MemberConnectLoginMessage;
import cn.lili.modules.member.entity.dos.Member; import cn.lili.modules.member.entity.dos.Member;
import cn.lili.modules.member.entity.dos.MemberSign; import cn.lili.modules.member.entity.dos.MemberSign;
import cn.lili.modules.member.entity.dto.MemberPointMessage; import cn.lili.modules.member.entity.dto.MemberPointMessage;
@ -55,10 +56,10 @@ public class MemberMessageListener implements RocketMQListener<MessageExt> {
*/ */
@Autowired @Autowired
private List<MemberLoginEvent> memberLoginEvents; private List<MemberLoginEvent> memberLoginEvents;
@Autowired @Autowired
private List<MemberInfoChangeEvent> memberInfoChangeEvents; private List<MemberInfoChangeEvent> memberInfoChangeEvents;
@Autowired
private List<MemberConnectLoginEvent> memberConnectLoginEvents;
@Override @Override
public void onMessage(MessageExt messageExt) { public void onMessage(MessageExt messageExt) {
@ -77,7 +78,7 @@ public class MemberMessageListener implements RocketMQListener<MessageExt> {
} }
} }
break; break;
//用户登录
case MEMBER_LOGIN: case MEMBER_LOGIN:
for (MemberLoginEvent memberLoginEvent : memberLoginEvents) { for (MemberLoginEvent memberLoginEvent : memberLoginEvents) {
@ -139,6 +140,20 @@ public class MemberMessageListener implements RocketMQListener<MessageExt> {
} }
} }
break; break;
//用户第三方登录
case MEMBER_CONNECT_LOGIN:
for (MemberConnectLoginEvent memberConnectLoginEvent : memberConnectLoginEvents) {
try {
MemberConnectLoginMessage memberConnectLoginMessage = JSONUtil.toBean(new String(messageExt.getBody()), MemberConnectLoginMessage.class);
memberConnectLoginEvent.memberConnectLogin(memberConnectLoginMessage.getMember(), memberConnectLoginMessage.getConnectAuthUser());
} catch (Exception e) {
log.error("会员{},在{}业务中,状态修改事件执行异常",
new String(messageExt.getBody()),
memberConnectLoginEvent.getClass().getName(),
e);
}
}
break;
default: default:
break; break;
} }

View File

@ -11,9 +11,9 @@ package cn.lili.modules.connect.config;
public enum ConnectAuthEnum implements ConnectAuth { public enum ConnectAuthEnum implements ConnectAuth {
/** /**
* 微信开放平台 * 微信公众号登录
*/ */
WECHAT { WECHAT_WAP {
@Override @Override
public String authorize() { public String authorize() {
return "https://open.weixin.qq.com/connect/oauth2/authorize"; return "https://open.weixin.qq.com/connect/oauth2/authorize";
@ -32,6 +32,7 @@ public enum ConnectAuthEnum implements ConnectAuth {
/** /**
* 微信开放平台 * 微信开放平台
* 微信PC登录
*/ */
WECHAT_PC { WECHAT_PC {
@Override @Override

View File

@ -67,6 +67,16 @@ public class ConnectAuthUser implements Serializable {
* 用户来源 * 用户来源
*/ */
private String source; private String source;
/**
* 用户来源
* 例如微信支付宝微博
*/
private String source1;
/**
* 类型
* 例如PCWAP小程序
*/
private String type;
/** /**
* 用户授权的token信息 * 用户授权的token信息
*/ */
@ -81,4 +91,9 @@ public class ConnectAuthUser implements Serializable {
*/ */
private ConnectAuthEnum connectEnum; private ConnectAuthEnum connectEnum;
/**
* 手机号
*/
private String phone;
} }

View File

@ -0,0 +1,14 @@
package cn.lili.modules.connect.entity.dto;
import cn.lili.modules.member.entity.dos.Member;
import lombok.Data;
/**
* 会员联合登录消息
*/
@Data
public class MemberConnectLoginMessage {
private Member member;
private ConnectAuthUser connectAuthUser;
}

View File

@ -15,8 +15,6 @@ public enum ConnectEnum {
WEIBO("微博联合登录"), WEIBO("微博联合登录"),
//只存放unionid //只存放unionid
WECHAT("微信联合登录"), WECHAT("微信联合登录"),
WECHAT_OPEN_ID("微信openid登录"),
WECHAT_MP_OPEN_ID("微信openid登录"),
ALIPAY("支付宝登录"), ALIPAY("支付宝登录"),
APPLE("苹果登录"); APPLE("苹果登录");

View File

@ -0,0 +1,24 @@
package cn.lili.modules.connect.entity.enums;
/**
* 联合登陆-渠道枚举
*
* @author Chopper
* @version v4.0
* @since 2020/11/25 18:20
*/
public enum SourceEnum {
WECHAT_PC_OPEN_ID("微信PC应用 openid登录"),
WECHAT_OFFIACCOUNT_OPEN_ID("微信公众号 openid登录"),
WECHAT_MP_OPEN_ID("微信小程序 openid登录"),
WECHAT_APP_OPEN_ID("微信APP openid登录"),
;
private final String description;
SourceEnum(String description) {
this.description = description;
}
}

View File

@ -10,6 +10,8 @@ import cn.lili.modules.connect.entity.dto.AuthToken;
import cn.lili.modules.connect.entity.dto.ConnectAuthUser; import cn.lili.modules.connect.entity.dto.ConnectAuthUser;
import cn.lili.modules.connect.entity.enums.AuthResponseStatus; import cn.lili.modules.connect.entity.enums.AuthResponseStatus;
import cn.lili.modules.connect.entity.enums.AuthUserGender; import cn.lili.modules.connect.entity.enums.AuthUserGender;
import cn.lili.modules.connect.entity.enums.ConnectEnum;
import cn.lili.modules.connect.entity.enums.SourceEnum;
import cn.lili.modules.connect.exception.AuthException; import cn.lili.modules.connect.exception.AuthException;
import cn.lili.common.utils.HttpUtils; import cn.lili.common.utils.HttpUtils;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
@ -56,10 +58,12 @@ public class BaseAuthWeChatPCRequest extends BaseAuthRequest {
.nickname(object.getString("nickname")) .nickname(object.getString("nickname"))
.avatar(object.getString("headimgurl")) .avatar(object.getString("headimgurl"))
.location(location) .location(location)
.uuid(authToken.getUnionId()) .uuid(authToken.getOpenId())
.gender(AuthUserGender.getWechatRealGender(object.getString("sex"))) .gender(AuthUserGender.getWechatRealGender(object.getString("sex")))
.token(authToken) .token(authToken)
.source(source.toString()) .source(source.toString())
.source1(ConnectEnum.WECHAT.name())
.type(SourceEnum.WECHAT_PC_OPEN_ID.name())
.build(); .build();
} }

View File

@ -10,6 +10,8 @@ import cn.lili.modules.connect.entity.dto.AuthToken;
import cn.lili.modules.connect.entity.dto.ConnectAuthUser; import cn.lili.modules.connect.entity.dto.ConnectAuthUser;
import cn.lili.modules.connect.entity.enums.AuthResponseStatus; import cn.lili.modules.connect.entity.enums.AuthResponseStatus;
import cn.lili.modules.connect.entity.enums.AuthUserGender; import cn.lili.modules.connect.entity.enums.AuthUserGender;
import cn.lili.modules.connect.entity.enums.ConnectEnum;
import cn.lili.modules.connect.entity.enums.SourceEnum;
import cn.lili.modules.connect.exception.AuthException; import cn.lili.modules.connect.exception.AuthException;
import cn.lili.modules.connect.util.GlobalAuthUtils; import cn.lili.modules.connect.util.GlobalAuthUtils;
import cn.lili.common.utils.HttpUtils; import cn.lili.common.utils.HttpUtils;
@ -23,7 +25,7 @@ import com.alibaba.fastjson.JSONObject;
*/ */
public class BaseAuthWeChatRequest extends BaseAuthRequest { public class BaseAuthWeChatRequest extends BaseAuthRequest {
public BaseAuthWeChatRequest(AuthConfig config, Cache cache) { public BaseAuthWeChatRequest(AuthConfig config, Cache cache) {
super(config, ConnectAuthEnum.WECHAT, cache); super(config, ConnectAuthEnum.WECHAT_WAP, cache);
} }
/** /**
@ -62,6 +64,8 @@ public class BaseAuthWeChatRequest extends BaseAuthRequest {
.gender(AuthUserGender.getWechatRealGender(object.getString("sex"))) .gender(AuthUserGender.getWechatRealGender(object.getString("sex")))
.token(authToken) .token(authToken)
.source(source.toString()) .source(source.toString())
.source1(ConnectEnum.WECHAT.name())
.type(SourceEnum.WECHAT_OFFIACCOUNT_OPEN_ID.name())
.build(); .build();
} }

View File

@ -28,27 +28,14 @@ public interface ConnectService extends IService<Connect> {
*/ */
String CONNECT_TYPE = "CONNECT_TYPE"; String CONNECT_TYPE = "CONNECT_TYPE";
/**
* 联合登陆
*
* @param type 类型
* @param unionid unionid
* @param longTerm 是否长时间有效
* @param uuid UUID
* @return token
* @throws NoPermissionException 不允许操作
*/
Token unionLoginCallback(String type, String unionid, String uuid, boolean longTerm) throws NoPermissionException;
/** /**
* 联合登陆对象直接登录 * 联合登陆对象直接登录
* *
* @param type 第三方登录类型
* @param authUser 第三方登录返回封装类 * @param authUser 第三方登录返回封装类
* @param uuid 用户uuid * @param uuid 用户uuid
* @return token * @return token
*/ */
Token unionLoginCallback(String type, ConnectAuthUser authUser, String uuid); Token unionLoginCallback(ConnectAuthUser authUser, String uuid);
/** /**
* 绑定 * 绑定
@ -86,15 +73,6 @@ public interface ConnectService extends IService<Connect> {
return CachePrefix.CONNECT_AUTH.getPrefix() + type + uuid; return CachePrefix.CONNECT_AUTH.getPrefix() + type + uuid;
} }
/**
* app联合登录 回调
*
* @param authUser 登录对象
* @param uuid uuid
* @return token
*/
Token appLoginCallback(ConnectAuthUser authUser, String uuid);
/** /**
* 微信一键登录 * 微信一键登录
@ -119,4 +97,12 @@ public interface ConnectService extends IService<Connect> {
* @param userId 会员id * @param userId 会员id
*/ */
void deleteByMemberId(String userId); void deleteByMemberId(String userId);
/**
* 绑定第三方平台用户
* @param userId 用户ID
* @param unionId 第三方平台用户ID
* @param type 平台类型
*/
void loginBindUser(String userId, String unionId, String type);
} }

View File

@ -18,6 +18,7 @@ import cn.lili.common.utils.CookieUtil;
import cn.lili.common.utils.HttpUtils; import cn.lili.common.utils.HttpUtils;
import cn.lili.modules.connect.entity.Connect; import cn.lili.modules.connect.entity.Connect;
import cn.lili.modules.connect.entity.dto.ConnectAuthUser; import cn.lili.modules.connect.entity.dto.ConnectAuthUser;
import cn.lili.modules.connect.entity.dto.MemberConnectLoginMessage;
import cn.lili.modules.connect.entity.dto.WechatMPLoginParams; import cn.lili.modules.connect.entity.dto.WechatMPLoginParams;
import cn.lili.modules.connect.entity.enums.ConnectEnum; import cn.lili.modules.connect.entity.enums.ConnectEnum;
import cn.lili.modules.connect.mapper.ConnectMapper; import cn.lili.modules.connect.mapper.ConnectMapper;
@ -31,10 +32,13 @@ import cn.lili.modules.system.entity.dto.connect.WechatConnectSetting;
import cn.lili.modules.system.entity.dto.connect.dto.WechatConnectSettingItem; import cn.lili.modules.system.entity.dto.connect.dto.WechatConnectSettingItem;
import cn.lili.modules.system.entity.enums.SettingEnum; import cn.lili.modules.system.entity.enums.SettingEnum;
import cn.lili.modules.system.service.SettingService; import cn.lili.modules.system.service.SettingService;
import cn.lili.rocketmq.RocketmqSendCallbackBuilder;
import cn.lili.rocketmq.tags.GoodsTagsEnum;
import cn.lili.rocketmq.tags.MemberTagsEnum; import cn.lili.rocketmq.tags.MemberTagsEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
@ -71,65 +75,21 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
@Autowired @Autowired
private Cache cache; private Cache cache;
/** /**
* RocketMQ 配置 * RocketMQ
*/
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* RocketMQ配置
*/ */
@Autowired @Autowired
private RocketmqCustomProperties rocketmqCustomProperties; private RocketmqCustomProperties rocketmqCustomProperties;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Token unionLoginCallback(String type, String unionid, String uuid, boolean longTerm) throws NoPermissionException { public Token unionLoginCallback(ConnectAuthUser authUser, String uuid) {
try { return this.unionLoginCallback(authUser, false);
LambdaQueryWrapper<Connect> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Connect::getUnionId, unionid);
queryWrapper.eq(Connect::getUnionType, type);
//查询绑定关系
Connect connect = this.getOne(queryWrapper);
if (connect == null) {
throw new NoPermissionException("未绑定用户");
}
//查询会员
Member member = memberService.getById(connect.getUserId());
//如果未绑定会员则把刚才查询到的联合登录表数据删除
if (member == null) {
this.remove(queryWrapper);
throw new NoPermissionException("未绑定用户");
}
return memberTokenGenerate.createToken(member, longTerm);
} catch (NoPermissionException e) {
log.error("联合登陆失败:", e);
throw e;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Token unionLoginCallback(String type, ConnectAuthUser authUser, String uuid) {
Token token;
try {
token = this.unionLoginCallback(type, authUser.getUuid(), uuid, false);
} catch (NoPermissionException e) {
if (AUTO_REGION) {
token = memberService.autoRegister(authUser);
return token;
} else {
//写入cookie
CookieUtil.addCookie(CONNECT_COOKIE, uuid, 1800, ThreadContextHolder.getHttpResponse());
CookieUtil.addCookie(CONNECT_TYPE, type, 1800, ThreadContextHolder.getHttpResponse());
//自动登录失败则把信息缓存起来
cache.put(ConnectService.cacheKey(type, uuid), authUser, 30L, TimeUnit.MINUTES);
throw new ServiceException(ResultCode.USER_NOT_BINDING);
}
} catch (Exception e) {
log.error("联合登陆异常:", e);
throw new ServiceException(ResultCode.ERROR);
}
return token;
} }
@Override @Override
@ -137,6 +97,8 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
AuthUser authUser = Objects.requireNonNull(UserContext.getCurrentUser()); AuthUser authUser = Objects.requireNonNull(UserContext.getCurrentUser());
Connect connect = new Connect(authUser.getId(), unionId, type); Connect connect = new Connect(authUser.getId(), unionId, type);
this.save(connect); this.save(connect);
} }
@Override @Override
@ -161,16 +123,6 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
return keys; return keys;
} }
@Override
@Transactional(rollbackFor = Exception.class)
public Token appLoginCallback(ConnectAuthUser authUser, String uuid) {
try {
return this.unionLoginCallback(authUser.getSource(), authUser.getUuid(), uuid, true);
} catch (NoPermissionException e) {
return memberService.autoRegister(authUser);
}
}
@Override @Override
@Transactional @Transactional
@ -226,40 +178,24 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
*/ */
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Token phoneMpBindAndLogin(String sessionKey, WechatMPLoginParams params, String openId, String unionId) { public Token phoneMpBindAndLogin(String sessionKey, WechatMPLoginParams params, String openId, String unionId) {
String encryptedData = params.getEncryptedData(); try {
String iv = params.getIv(); String encryptedData = params.getEncryptedData();
JSONObject userInfo = this.getUserInfo(encryptedData, sessionKey, iv); String iv = params.getIv();
log.info("联合登陆返回:{}", userInfo.toString()); JSONObject userInfo = this.getUserInfo(encryptedData, sessionKey, iv);
String phone = (String) userInfo.get("purePhoneNumber"); log.info("联合登陆返回:{}", userInfo.toString());
String phone = (String) userInfo.get("purePhoneNumber");
//手机号登录 ConnectAuthUser connectAuthUser = new ConnectAuthUser();
LambdaQueryWrapper<Member> lambdaQueryWrapper = new LambdaQueryWrapper<>(); connectAuthUser.setUuid(openId);
lambdaQueryWrapper.eq(Member::getMobile, phone); connectAuthUser.setNickname(params.getNickName());
Member member = memberService.getOne(lambdaQueryWrapper); connectAuthUser.setAvatar(params.getImage());
//如果不存在会员则进行绑定微信openid unionid并且登录 connectAuthUser.setUsername("m" + phone);
if (member != null) { connectAuthUser.setPhone(phone);
bindMpMember(openId, unionId, member); return this.unionLoginCallback(connectAuthUser, true);
return memberTokenGenerate.createToken(member, true); } catch (Exception e) {
e.printStackTrace();
} }
return null;
//如果没有会员则根据手机号注册会员
Member newMember = new Member("m" + phone, "111111", phone, params.getNickName(), params.getImage());
memberService.save(newMember);
newMember = memberService.findByUsername(newMember.getUsername());
//判定有没有邀请人并且写入
UserContext.settingInviter(newMember.getId(), cache);
bindMpMember(openId, unionId, newMember);
//判定有没有邀请人并且写入
UserContext.settingInviter(newMember.getId(), cache);
// 发送会员注册信息
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("new member register", rocketmqCustomProperties.getMemberTopic(), MemberTagsEnum.MEMBER_REGISTER.name(), newMember));
return memberTokenGenerate.createToken(newMember, true);
} }
@Override @Override
@ -280,47 +216,72 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> impl
} }
/** /**
* 会员绑定 绑定微信小程序 * 成功登录则检测cookie中的信息进行会员绑定
* <p>
* 如果openid 已经绑定其他账号则这里不作处理如果未绑定则绑定最新的会员
* 这样微信小程序注册之后其他app 公众号页面都可以实现绑定自动登录功能
* </p>
* *
* @param openId 微信openid * @param userId 用户ID
* @param unionId 微信unionid * @param unionId 第三方用户ID
* @param member 会员 * @param type 类型
*/ */
private void bindMpMember(String openId, String unionId, Member member) { @Override
public void loginBindUser(String userId, String unionId, String type) {
Connect connect = this.queryConnect(
//如果unionid 不为空 则为账号绑定unionid ConnectQueryDTO.builder().unionId(unionId).unionType(type).build()
if (CharSequenceUtil.isNotEmpty(unionId)) { );
LambdaQueryWrapper<Connect> lambdaQueryWrapper = new LambdaQueryWrapper(); if (connect == null) {
lambdaQueryWrapper.eq(Connect::getUnionId, unionId); connect = new Connect(userId, unionId, type);
lambdaQueryWrapper.eq(Connect::getUnionType, ConnectEnum.WECHAT.name()); this.save(connect);
List<Connect> connects = this.list(lambdaQueryWrapper);
if (connects.isEmpty()) {
Connect connect = new Connect();
connect.setUnionId(unionId);
connect.setUserId(member.getId());
connect.setUnionType(ConnectEnum.WECHAT.name());
this.save(connect);
}
}//如果openid 不为空 则为账号绑定openid
if (CharSequenceUtil.isNotEmpty(openId)) {
LambdaQueryWrapper<Connect> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(Connect::getUnionId, openId);
lambdaQueryWrapper.eq(Connect::getUnionType, ConnectEnum.WECHAT_MP_OPEN_ID.name());
List<Connect> connects = this.list(lambdaQueryWrapper);
if (connects.isEmpty()) {
Connect connect = new Connect();
connect.setUnionId(openId);
connect.setUserId(member.getId());
connect.setUnionType(ConnectEnum.WECHAT_MP_OPEN_ID.name());
this.save(connect);
}
} }
}
/**
* 第三方联合登陆
* 1.判断是否使用开放平台
* 1.1如果使用开放平台则使用UnionId进行登录
* 1.2如果不适用开放平台则使用OpenId进行登录
* <p>
* 2.用户登录后判断绑定OpenId
*
* @param authUser 第三方登录封装类
* @param longTerm 是否长时间有效
* @return token
* @throws NoPermissionException 不允许操作
*/
private Token unionLoginCallback(ConnectAuthUser authUser, boolean longTerm) {
//使用UnionId登录
try {
LambdaQueryWrapper<Connect> queryWrapper = new LambdaQueryWrapper<Connect>()
.eq(Connect::getUnionId, authUser.getToken().getUnionId())
.eq(Connect::getUnionType, authUser.getSource1());
//查询绑定关系
Connect connect = this.getOne(queryWrapper);
Member member = new Member();
if (connect == null) {
member = memberService.autoRegister(authUser);
} else {
//查询会员
member = memberService.getById(connect.getUserId());
//如果未绑定会员则把刚才查询到的联合登录表数据删除
if (member == null) {
this.remove(queryWrapper);
member = memberService.autoRegister(authUser);
}
}
//发送用户第三方登录消息
MemberConnectLoginMessage memberConnectLoginMessage = new MemberConnectLoginMessage();
memberConnectLoginMessage.setMember(member);
memberConnectLoginMessage.setConnectAuthUser(authUser);
String destination = rocketmqCustomProperties.getMemberTopic() + ":" + MemberTagsEnum.MEMBER_CONNECT_LOGIN.name();
//发送用户第三方登录消息
rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(memberConnectLoginMessage), RocketmqSendCallbackBuilder.commonCallback());
return memberTokenGenerate.createToken(member, longTerm);
} catch (Exception e) {
log.error("联合登陆失败:", e);
throw e;
}
} }
/** /**

View File

@ -66,6 +66,7 @@ public class ConnectUtil {
/** /**
* 回调地址获取 * 回调地址获取
*
* @param connectAuthEnum 用户枚举 * @param connectAuthEnum 用户枚举
* @return 回调地址 * @return 回调地址
*/ */
@ -75,9 +76,11 @@ public class ConnectUtil {
/** /**
* 登录回调 * 登录回调
* 此方法处理第三方登录回调
* 场景PCWAP(微信公众号)
* *
* @param type * @param type 类型
* @param callback * @param callback 回调参数
* @param httpServletResponse * @param httpServletResponse
* @param httpServletRequest * @param httpServletRequest
* @throws IOException * @throws IOException
@ -89,9 +92,8 @@ public class ConnectUtil {
//联合登陆处理如果响应正常则录入响应结果到redis //联合登陆处理如果响应正常则录入响应结果到redis
if (response.ok()) { if (response.ok()) {
ConnectAuthUser authUser = response.getData(); ConnectAuthUser authUser = response.getData();
Token token;
try { try {
token = connectService.unionLoginCallback(type, authUser, callback.getState()); Token token = connectService.unionLoginCallback(authUser, callback.getState());
resultMessage = ResultUtil.data(token); resultMessage = ResultUtil.data(token);
} catch (ServiceException e) { } catch (ServiceException e) {
throw new ServiceException(ResultCode.ERROR, e.getMessage()); throw new ServiceException(ResultCode.ERROR, e.getMessage());
@ -112,7 +114,7 @@ public class ConnectUtil {
try { try {
httpServletResponse.sendRedirect(url); httpServletResponse.sendRedirect(url);
} catch (Exception e) { } catch (Exception e) {
log.error("登录回调错误",e); log.error("登录回调错误", e);
} }
} }
@ -145,7 +147,7 @@ public class ConnectUtil {
} }
AuthRequest authRequest = null; AuthRequest authRequest = null;
switch (authInterface) { switch (authInterface) {
case WECHAT: { case WECHAT_WAP: {
//寻找配置 //寻找配置
Setting setting = settingService.get(SettingEnum.WECHAT_CONNECT.name()); Setting setting = settingService.get(SettingEnum.WECHAT_CONNECT.name());
WechatConnectSetting wechatConnectSetting = JSONUtil.toBean(setting.getSettingValue(), WechatConnectSetting.class); WechatConnectSetting wechatConnectSetting = JSONUtil.toBean(setting.getSettingValue(), WechatConnectSetting.class);
@ -165,6 +167,7 @@ public class ConnectUtil {
//寻找配置 //寻找配置
Setting setting = settingService.get(SettingEnum.WECHAT_CONNECT.name()); Setting setting = settingService.get(SettingEnum.WECHAT_CONNECT.name());
WechatConnectSetting wechatConnectSetting = JSONUtil.toBean(setting.getSettingValue(), WechatConnectSetting.class); WechatConnectSetting wechatConnectSetting = JSONUtil.toBean(setting.getSettingValue(), WechatConnectSetting.class);
for (WechatConnectSettingItem wechatConnectSettingItem : wechatConnectSetting.getWechatConnectSettingItems()) { for (WechatConnectSettingItem wechatConnectSettingItem : wechatConnectSetting.getWechatConnectSettingItems()) {
if (wechatConnectSettingItem.getClientType().equals(ClientTypeEnum.PC.name())) { if (wechatConnectSettingItem.getClientType().equals(ClientTypeEnum.PC.name())) {
authRequest = new BaseAuthWeChatPCRequest(AuthConfig.builder() authRequest = new BaseAuthWeChatPCRequest(AuthConfig.builder()
@ -178,10 +181,10 @@ public class ConnectUtil {
break; break;
} }
case QQ: case QQ:
//寻找配置 //寻找配置
Setting setting = settingService.get(SettingEnum.QQ_CONNECT.name()); Setting setting = settingService.get(SettingEnum.QQ_CONNECT.name());
QQConnectSetting qqConnectSetting = JSONUtil.toBean(setting.getSettingValue(), QQConnectSetting.class); QQConnectSetting qqConnectSetting = JSONUtil.toBean(setting.getSettingValue(), QQConnectSetting.class);
for (QQConnectSettingItem qqConnectSettingItem : qqConnectSetting.getQqConnectSettingItemList()) { for (QQConnectSettingItem qqConnectSettingItem : qqConnectSetting.getQqConnectSettingItemList()) {
if (qqConnectSettingItem.getClientType().equals(ClientTypeEnum.PC.name())) { if (qqConnectSettingItem.getClientType().equals(ClientTypeEnum.PC.name())) {
authRequest = new BaseAuthQQRequest(AuthConfig.builder() authRequest = new BaseAuthQQRequest(AuthConfig.builder()

View File

@ -15,6 +15,7 @@ import cn.lili.modules.member.entity.vo.QRLoginResultVo;
import cn.lili.modules.member.entity.vo.QRCodeLoginSessionVo; import cn.lili.modules.member.entity.vo.QRCodeLoginSessionVo;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import org.elasticsearch.monitor.os.OsStats;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -175,12 +176,12 @@ public interface MemberService extends IService<Member> {
IPage<MemberVO> getMemberPage(MemberSearchVO memberSearchVO, PageVO page); IPage<MemberVO> getMemberPage(MemberSearchVO memberSearchVO, PageVO page);
/** // /**
* 一键注册会员 // * 一键注册会员
* // *
* @return // * @return
*/ // */
Token autoRegister(); // Token autoRegister();
/** /**
* 一键注册会员 * 一键注册会员
@ -188,7 +189,7 @@ public interface MemberService extends IService<Member> {
* @param authUser 联合登录用户 * @param authUser 联合登录用户
* @return Token * @return Token
*/ */
Token autoRegister(ConnectAuthUser authUser); Member autoRegister(ConnectAuthUser authUser);
/** /**
* 刷新token * 刷新token

View File

@ -224,7 +224,7 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
@Override @Override
@Transactional @Transactional
public Token autoRegister(ConnectAuthUser authUser) { public Member autoRegister(ConnectAuthUser authUser) {
if (CharSequenceUtil.isEmpty(authUser.getNickname())) { if (CharSequenceUtil.isEmpty(authUser.getNickname())) {
authUser.setNickname("临时昵称"); authUser.setNickname("临时昵称");
@ -236,11 +236,11 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
String username = UuidUtils.getUUID(); String username = UuidUtils.getUUID();
Member member = new Member(username, UuidUtils.getUUID(), authUser.getAvatar(), authUser.getNickname(), Member member = new Member(username, UuidUtils.getUUID(), authUser.getAvatar(), authUser.getNickname(),
authUser.getGender() != null ? Convert.toInt(authUser.getGender().getCode()) : 0); authUser.getGender() != null ? Convert.toInt(authUser.getGender().getCode()) : 0);
registerHandler(member);
member.setPassword(DEFAULT_PASSWORD); member.setPassword(DEFAULT_PASSWORD);
//绑定登录方式 // 发送会员注册信息
loginBindUser(member, authUser.getUuid(), authUser.getSource()); registerHandler(member);
return memberTokenGenerate.createToken(member, false);
return member;
} catch (ServiceException e) { } catch (ServiceException e) {
log.error("自动注册服务抛出异常:", e); log.error("自动注册服务抛出异常:", e);
throw e; throw e;
@ -250,12 +250,12 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
} }
} }
@Override // @Override
@Transactional // @Transactional
public Token autoRegister() { // public Token autoRegister() {
ConnectAuthUser connectAuthUser = this.checkConnectUser(); // ConnectAuthUser connectAuthUser = this.checkConnectUser();
return this.autoRegister(connectAuthUser); // return this.autoRegister(connectAuthUser);
} // }
@Override @Override
public Token refreshToken(String refreshToken) { public Token refreshToken(String refreshToken) {
@ -293,7 +293,6 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
//保存会员 //保存会员
this.save(member); this.save(member);
// 发送会员注册信息 // 发送会员注册信息
applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("new member register", rocketmqCustomProperties.getMemberTopic(), MemberTagsEnum.MEMBER_REGISTER.name(), member)); applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("new member register", rocketmqCustomProperties.getMemberTopic(), MemberTagsEnum.MEMBER_REGISTER.name(), member));
} }
@ -557,23 +556,6 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
return null; return null;
} }
/**
* 成功登录则检测cookie中的信息进行会员绑定
*
* @param member 会员
* @param unionId unionId
* @param type 状态
*/
private void loginBindUser(Member member, String unionId, String type) {
Connect connect = connectService.queryConnect(
ConnectQueryDTO.builder().unionId(unionId).unionType(type).build()
);
if (connect == null) {
connect = new Connect(member.getId(), unionId, type);
connectService.save(connect);
}
}
/** /**
* 成功登录则检测cookie中的信息进行会员绑定 * 成功登录则检测cookie中的信息进行会员绑定
* *
@ -612,42 +594,42 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> impleme
} }
/** // /**
* 检测是否可以绑定第三方联合登陆 // * 检测是否可以绑定第三方联合登陆
* 返回null原因 // * 返回null原因
* 包含原因1redis中已经没有联合登陆信息 2已绑定其他账号 // * 包含原因1redis中已经没有联合登陆信息 2已绑定其他账号
* // *
* @return 返回对象则代表可以进行绑定第三方会员返回null则表示联合登陆无法继续 // * @return 返回对象则代表可以进行绑定第三方会员返回null则表示联合登陆无法继续
*/ // */
private ConnectAuthUser checkConnectUser() { // private ConnectAuthUser checkConnectUser() {
//获取cookie存储的信息 // //获取cookie存储的信息
String uuid = CookieUtil.getCookie(ConnectService.CONNECT_COOKIE, ThreadContextHolder.getHttpRequest()); // String uuid = CookieUtil.getCookie(ConnectService.CONNECT_COOKIE, ThreadContextHolder.getHttpRequest());
String connectType = CookieUtil.getCookie(ConnectService.CONNECT_TYPE, ThreadContextHolder.getHttpRequest()); // String connectType = CookieUtil.getCookie(ConnectService.CONNECT_TYPE, ThreadContextHolder.getHttpRequest());
//
//如果联合登陆存储了信息 // //如果联合登陆存储了信息
if (CharSequenceUtil.isNotEmpty(uuid) && CharSequenceUtil.isNotEmpty(connectType)) { // if (CharSequenceUtil.isNotEmpty(uuid) && CharSequenceUtil.isNotEmpty(connectType)) {
//枚举 联合登陆类型获取 // //枚举 联合登陆类型获取
ConnectAuthEnum authInterface = ConnectAuthEnum.valueOf(connectType); // ConnectAuthEnum authInterface = ConnectAuthEnum.valueOf(connectType);
//
ConnectAuthUser connectAuthUser = getConnectAuthUser(uuid, connectType); // ConnectAuthUser connectAuthUser = getConnectAuthUser(uuid, connectType);
if (connectAuthUser == null) { // if (connectAuthUser == null) {
throw new ServiceException(ResultCode.USER_OVERDUE_CONNECT_ERROR); // throw new ServiceException(ResultCode.USER_OVERDUE_CONNECT_ERROR);
} // }
//检测是否已经绑定过用户 // //检测是否已经绑定过用户
Connect connect = connectService.queryConnect( // Connect connect = connectService.queryConnect(
ConnectQueryDTO.builder().unionType(connectType).unionId(connectAuthUser.getUuid()).build() // ConnectQueryDTO.builder().unionType(connectType).unionId(connectAuthUser.getUuid()).build()
); // );
//没有关联则返回true表示可以继续绑定 // //没有关联则返回true表示可以继续绑定
if (connect == null) { // if (connect == null) {
connectAuthUser.setConnectEnum(authInterface); // connectAuthUser.setConnectEnum(authInterface);
return connectAuthUser; // return connectAuthUser;
} else { // } else {
throw new ServiceException(ResultCode.USER_CONNECT_BANDING_ERROR); // throw new ServiceException(ResultCode.USER_CONNECT_BANDING_ERROR);
} // }
} else { // } else {
throw new ServiceException(ResultCode.USER_CONNECT_NOT_EXIST_ERROR); // throw new ServiceException(ResultCode.USER_CONNECT_NOT_EXIST_ERROR);
} // }
} // }
@Override @Override
public long getMemberNum(MemberSearchVO memberSearchVO) { public long getMemberNum(MemberSearchVO memberSearchVO) {

View File

@ -30,7 +30,11 @@ public enum MemberTagsEnum {
/** /**
* 会员积分变动 * 会员积分变动
*/ */
MEMBER_POINT_CHANGE("会员积分变动"); MEMBER_POINT_CHANGE("会员积分变动"),
/**
* 会员使用联合登录
*/
MEMBER_CONNECT_LOGIN("会员使用联合登录");
private final String description; private final String description;