Compare commits
27 Commits
aed0db32f7
...
jdk25_dev
Author | SHA1 | Date | |
---|---|---|---|
cce6bfd896 | |||
a8aa415858 | |||
5ad43fd617 | |||
600c439a43 | |||
a762e35456 | |||
69dde07fc9 | |||
1112abb97c | |||
904859d496 | |||
8aab7d11fb | |||
b29dcfedd7 | |||
4985074412 | |||
29f7e88f17 | |||
2b90820c07 | |||
7e6f17acad | |||
3176cf50b6 | |||
aec5d86119 | |||
daefb00c15 | |||
7fc64a660c | |||
a607e1098d | |||
2b385a036b | |||
ec0d3e1c8c | |||
64f9daf8e4 | |||
7b1d87cd75 | |||
1d180cf261 | |||
7790cab3b0 | |||
9452221e87 | |||
2e3b031780 |
@@ -1,51 +0,0 @@
|
||||
package com.accompany.admin.service.activity;
|
||||
|
||||
import com.accompany.business.model.activity.PageActivity;
|
||||
import com.accompany.business.service.activity.PageActivityService;
|
||||
import com.accompany.business.vo.activities.PageActivityVO;
|
||||
import com.accompany.core.util.BeanUtils;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
|
||||
/**
|
||||
* 页面静态活动配置 service
|
||||
*
|
||||
* @author linuxea
|
||||
* @date 2019/10/9 11:01
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class StaticActivityPageService {
|
||||
private final PageActivityService pageActivityService;
|
||||
|
||||
@Autowired
|
||||
public StaticActivityPageService(PageActivityService pageActivityService) {
|
||||
this.pageActivityService = pageActivityService;
|
||||
}
|
||||
|
||||
public IPage<PageActivity> queryList(Integer pageNumber, Integer pageSize) {
|
||||
return pageActivityService.pageList(null, pageNumber, pageSize);
|
||||
}
|
||||
|
||||
public void save(PageActivityVO pageActivityVo) {
|
||||
PageActivity pageActivity = BeanUtils.map(pageActivityVo, PageActivity.class);
|
||||
pageActivity.setCreateTime(Calendar.getInstance().getTime());
|
||||
pageActivity.setUpdateTime(Calendar.getInstance().getTime());
|
||||
pageActivityService.save(pageActivity);
|
||||
}
|
||||
|
||||
public void deleteByActivityId(Integer id) {
|
||||
pageActivityService.removeById(id);
|
||||
}
|
||||
|
||||
public Boolean existByCode(String actCode) {
|
||||
return pageActivityService.countByCode(actCode) > 0;
|
||||
}
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
package com.accompany.admin.controller.activity;
|
||||
|
||||
import com.accompany.admin.controller.BaseController;
|
||||
import com.accompany.admin.service.activity.StaticActivityPageService;
|
||||
import com.accompany.business.model.activity.PageActivity;
|
||||
import com.accompany.business.vo.activities.PageActivityVO;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 静态活动配置
|
||||
*
|
||||
* @author linuxea
|
||||
* @date 2019/10/9
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/admin/act/static")
|
||||
public class StaticActivityPageController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private StaticActivityPageService staticActivityPageService;
|
||||
|
||||
|
||||
/**
|
||||
* 分页列表
|
||||
*
|
||||
* @param pageNumber 页码
|
||||
* @param pageSize 页长
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public void queryList(@RequestParam("pageNumber") Integer pageNumber, @RequestParam("pageSize") Integer pageSize) {
|
||||
IPage<PageActivity> pageInfo = this.staticActivityPageService.queryList(pageNumber, pageSize);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("total", pageInfo.getTotal());
|
||||
jsonObject.put("rows", pageInfo.getRecords());
|
||||
writeJson(jsonObject.toJSONString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param pageActivity
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/save")
|
||||
public BusiResult saveOperationAct(PageActivityVO pageActivity) {
|
||||
Boolean exist = staticActivityPageService.existByCode(pageActivity.getCode());
|
||||
if (exist) {
|
||||
return new BusiResult(BusiStatus.CODE_DUPLICATE);
|
||||
}
|
||||
staticActivityPageService.save(pageActivity);
|
||||
return new BusiResult<>(BusiStatus.SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param id 静态活动 id
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping(value = "/delete")
|
||||
public BusiResult delOperationAct(Integer id) {
|
||||
staticActivityPageService.deleteByActivityId(id);
|
||||
return new BusiResult(BusiStatus.SUCCESS);
|
||||
}
|
||||
}
|
@@ -73,33 +73,34 @@ public class RoomBoomAwardRecordAdminController extends BaseController {
|
||||
|
||||
//1 创建IPage分页对象,设置分页参数
|
||||
IPage<RoomBoomSign> page=new Page<>(params.getPageNo(),params.getPageSize());
|
||||
Long uid = null;
|
||||
Long roomUid = null;
|
||||
LambdaQueryWrapper<RoomBoomSign> wrapper = new LambdaQueryWrapper<>();
|
||||
if (params.getRoomErbanNo() != null){
|
||||
Users erbanNo = usersService.getUserByErbanNo(params.getRoomErbanNo());
|
||||
if (erbanNo == null) {
|
||||
throw new AdminServiceException(BusiStatus.SERVERERROR, "房间id不存在");
|
||||
}
|
||||
roomUid = erbanNo.getUid();
|
||||
wrapper.eq(RoomBoomSign::getRoomUid,erbanNo.getUid());
|
||||
}
|
||||
if (params.getErbanNo() != null){
|
||||
Users erbanNo = usersService.getUserByErbanNo(params.getErbanNo());
|
||||
if (erbanNo == null) {
|
||||
throw new AdminServiceException(BusiStatus.SERVERERROR, "触发者id不存在");
|
||||
}
|
||||
uid = erbanNo.getUid();
|
||||
wrapper.eq(RoomBoomSign::getUid,erbanNo.getUid());
|
||||
}
|
||||
if (params.getLevel() != null){
|
||||
wrapper.eq(RoomBoomSign::getLevel,params.getLevel());
|
||||
}
|
||||
Date startTime = null, endTime = null;
|
||||
if (StringUtils.isNotEmpty(params.getStartTime())){
|
||||
startTime = DateUtil.parseDateTime(params.getStartTime());
|
||||
wrapper.ge(RoomBoomSign::getCreateTime, (Date)DateUtil.parseDateTime(params.getStartTime()));
|
||||
}
|
||||
if (StringUtils.isNotEmpty(params.getEndTime())){
|
||||
endTime = DateUtil.parseDateTime(params.getEndTime());
|
||||
wrapper.le(RoomBoomSign::getCreateTime, (Date)DateUtil.parseDateTime(params.getEndTime()));
|
||||
}
|
||||
wrapper.eq(RoomBoomSign::getStatus,2);
|
||||
wrapper.orderByDesc(RoomBoomSign::getId);
|
||||
//2 执行分页查询
|
||||
IPage<RoomBoomSign> boomSignIPage = roomBoomSignService.list(page, uid, roomUid, params.getLevel(),
|
||||
startTime, endTime, params.getPartitionId());
|
||||
|
||||
IPage<RoomBoomSign> boomSignIPage = roomBoomSignService.page(page, wrapper);
|
||||
Page<RoomBoomSignVO> resultVo = new Page<>();
|
||||
resultVo.setTotal(boomSignIPage.getTotal());
|
||||
List<RoomBoomSignVO> roomBoomSignVOS = new ArrayList<>();
|
||||
|
@@ -76,6 +76,4 @@ public interface UsersMapper {
|
||||
|
||||
|
||||
List<Users> listUid(@Param("start") Integer start, @Param("len") Integer len);
|
||||
|
||||
Integer recharegeCount(@Param("uid") Long uid);
|
||||
}
|
@@ -57,16 +57,6 @@ public class AccountService extends ServiceImpl<AccountMapper, Account> {
|
||||
return accounts.get(0);
|
||||
}
|
||||
|
||||
public Account getAccount(String phone) {
|
||||
Account account = getAccountByPhone(phone);
|
||||
if (account == null) {
|
||||
if (!CommonUtil.checkValidPhone(phone)) {
|
||||
account = getAccountByErBanNo(Long.valueOf(phone));
|
||||
}
|
||||
}
|
||||
return account;
|
||||
}
|
||||
|
||||
public Account getAccountByPhone(String phone) {
|
||||
QueryWrapper<Account> wrapper = new QueryWrapper<>();
|
||||
wrapper.lambda().eq(Account::getPhone, phone);
|
||||
@@ -145,7 +135,7 @@ public class AccountService extends ServiceImpl<AccountMapper, Account> {
|
||||
return accountList;
|
||||
}
|
||||
|
||||
public String refreshAndGetNetEaseToken(Account account) throws Exception {
|
||||
public String refreshAndGetNetEaseToken(Account account) {
|
||||
TokenRet tokenRet = netEaseService.refreshToken(account.getUid().toString());
|
||||
//未注册自动注册云信
|
||||
if (tokenRet != null && StrUtil.isNotEmpty(tokenRet.getDesc()) &&tokenRet.getDesc().contains("not register")) {
|
||||
@@ -154,20 +144,6 @@ public class AccountService extends ServiceImpl<AccountMapper, Account> {
|
||||
return (String) tokenRet.getInfo().get("token");
|
||||
}
|
||||
|
||||
public Account refreshNetEaseTokne(Long uid) throws Exception {
|
||||
Account account = getById(uid);
|
||||
String uidStr = String.valueOf(account.getUid());
|
||||
TokenRet tokenRet = netEaseService.refreshToken(uidStr);
|
||||
String token = (String) tokenRet.getInfo().get("token");
|
||||
Account accountUpdate = new Account();
|
||||
accountUpdate.setUid(account.getUid());
|
||||
accountUpdate.setNeteaseToken(token);
|
||||
accountUpdate.setErbanNo(account.getErbanNo());
|
||||
accountUpdate.setDeviceId(account.getDeviceId());
|
||||
save(accountUpdate);
|
||||
return accountUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初次设置
|
||||
*
|
||||
|
@@ -22,6 +22,7 @@ import com.google.gson.reflect.TypeToken;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -522,9 +523,4 @@ public class UsersBaseService extends BaseService {
|
||||
deleteUserRelateCache(uid.toString());
|
||||
}
|
||||
|
||||
|
||||
public Integer rechargeUserCount(Long uid) {
|
||||
return usersMapper.recharegeCount(uid);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,116 +0,0 @@
|
||||
package com.accompany.core.util;
|
||||
|
||||
|
||||
import com.accompany.common.config.WebSecurityConfig;
|
||||
import com.accompany.core.model.Account;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.JwtBuilder;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Created by yuanyi on 2019/2/21.
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class JwtUtils {
|
||||
|
||||
/**
|
||||
* 用户登录成功后生成Jwt
|
||||
* 使用Hs256算法 私匙使用用户密码
|
||||
* @param ttlMillis jwt过期时间
|
||||
* @return
|
||||
*/
|
||||
public String createJWT(Long ttlMillis, Long uid) {
|
||||
//指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。
|
||||
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
|
||||
|
||||
//生成JWT的时间
|
||||
long nowMillis = System.currentTimeMillis();
|
||||
Date now = new Date(nowMillis);
|
||||
|
||||
//创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)
|
||||
Map<String, Object> claims = new HashMap<String, Object>();
|
||||
claims.put("uid", uid);
|
||||
|
||||
//生成签名的时候使用的秘钥secret,这个方法本地封装了的,一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
|
||||
// String key = PropertyUtil.getProperty("jwtH5Key");
|
||||
String key = WebSecurityConfig.jwtWebKey;
|
||||
|
||||
//生成签发人,这里以平台号为签发人
|
||||
String subject = uid.toString();
|
||||
|
||||
|
||||
|
||||
//下面就是在为payload添加各种标准声明和私有声明了
|
||||
//这里其实就是new一个JwtBuilder,设置jwt的body
|
||||
JwtBuilder builder = Jwts.builder()
|
||||
//如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
|
||||
.setClaims(claims)
|
||||
//设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
|
||||
.setId(UUID.randomUUID().toString())
|
||||
//iat: jwt的签发时间
|
||||
.setIssuedAt(now)
|
||||
//代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。
|
||||
.setSubject(subject)
|
||||
//设置签名使用的签名算法和签名使用的秘钥
|
||||
.signWith(signatureAlgorithm, key);
|
||||
if (ttlMillis >= 0) {
|
||||
long expMillis = nowMillis + ttlMillis;
|
||||
Date exp = new Date(expMillis);
|
||||
//设置过期时间
|
||||
builder.setExpiration(exp);
|
||||
}
|
||||
return builder.compact();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Token的解密
|
||||
* @param token 加密后的token
|
||||
* @return
|
||||
*/
|
||||
public Claims parseJWT(String token) {
|
||||
//签名秘钥,和生成的签名的秘钥一模一样
|
||||
String key = WebSecurityConfig.jwtWebKey;
|
||||
|
||||
//得到DefaultJwtParser
|
||||
Claims claims = Jwts.parser()
|
||||
//设置签名的秘钥
|
||||
.setSigningKey(key)
|
||||
//设置需要解析的jwt
|
||||
.parseClaimsJws(token).getBody();
|
||||
return claims;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验token
|
||||
* 在这里可以使用官方的校验,我这里校验的是token中携带的密码于数据库一致的话就校验通过
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public Boolean isVerify(String token, Account account) {
|
||||
//签名秘钥,和生成的签名的秘钥一模一样
|
||||
String key = WebSecurityConfig.jwtWebKey;
|
||||
|
||||
//得到DefaultJwtParser
|
||||
Claims claims = Jwts.parser()
|
||||
//设置签名的秘钥
|
||||
.setSigningKey(key)
|
||||
//设置需要解析的jwt
|
||||
.parseClaimsJws(token).getBody();
|
||||
|
||||
if (claims.get("password").equals(account.getPassword())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -1082,8 +1082,4 @@
|
||||
/* SHARDINGSPHERE_HINT: WRITE_ROUTE_ONLY=true */
|
||||
select uid, partition_id partitionId from users order by uid asc limit #{start},#{len}
|
||||
</select>
|
||||
|
||||
<select id="recharegeCount" resultType="java.lang.Integer">
|
||||
select ifnull(count(1),0) from recharge_user where uid = #{uid}
|
||||
</select>
|
||||
</mapper>
|
@@ -640,7 +640,7 @@ public enum BusiStatus {
|
||||
|
||||
DEVICE_ERROR(500, "设备为空"),
|
||||
|
||||
|
||||
REGISTER_NETEASE_FAIL(500, "注册云信IM账号失败"),
|
||||
UPDATE_NETEASE_ROOM_FAIL(500, "云信聊天室信息更新失败"),
|
||||
|
||||
|
||||
@@ -988,7 +988,6 @@ public enum BusiStatus {
|
||||
ROOM_DAY_DIAMOND_REWARD_DATE_CHECK(500, "TODAY NOT ALLOW RECEIVE"),
|
||||
GUILD_USD_OPT_LIMIT(500, "该交易类型已达到本周交易次数上限"),
|
||||
GUILD_MEMBER_REMOVE_LIMIT(500, "仅在每个月1号、2号、3号才可以移除主播"),
|
||||
H5_RECHARGE_USER_NOT_OPEN(1404, "Your account has not enabled this function yet, so it cannot be used."),
|
||||
;
|
||||
|
||||
private final int value;
|
||||
|
@@ -1,68 +0,0 @@
|
||||
package com.accompany.common.utils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class JsonUtil {
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
private static ObjectMapper objectMapperInner;
|
||||
|
||||
@PostConstruct
|
||||
private void setObjectMapperInner() {
|
||||
objectMapperInner = objectMapper;
|
||||
}
|
||||
|
||||
public static <T> T parseToClass(String jsonString, Class<T> tClass) {
|
||||
try {
|
||||
return objectMapperInner.readValue(jsonString, tClass);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String parseToString(Object o) {
|
||||
try {
|
||||
return objectMapperInner.writeValueAsString(o);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isJsonObject(String json) {
|
||||
try {
|
||||
return objectMapperInner.readTree(json).isObject();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isJsonArray(String json) {
|
||||
try {
|
||||
return objectMapperInner.readTree(json).isArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> List<T> parseArray(String json, Class<T> tClass) {
|
||||
try {
|
||||
return objectMapperInner.readValue(json, objectMapperInner.getTypeFactory()
|
||||
.constructCollectionType(List.class, tClass));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
package com.accompany.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by yuanyi on 2019/2/23.
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface H5Authorization {
|
||||
}
|
@@ -1,9 +1,8 @@
|
||||
package com.accompany.core.util;
|
||||
|
||||
import com.accompany.core.base.SpringContextHolder;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
@@ -17,12 +16,7 @@ import java.io.IOException;
|
||||
public class JsonUtil {
|
||||
|
||||
private static ObjectMapper getMapper() {
|
||||
ObjectMapper bean = new ObjectMapper();
|
||||
//反序列化忽略多余属性
|
||||
bean.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
//如果是空对象的时候,不抛异常
|
||||
bean.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
return bean;
|
||||
return SpringContextHolder.getBean(ObjectMapper.class);
|
||||
}
|
||||
|
||||
public static <T> T parseToClass(String jsonString, Class<T> tClass) {
|
||||
|
@@ -5,7 +5,6 @@ import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.constant.SmsConstant;
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.RandomUtil;
|
||||
import com.accompany.common.utils.StringUtils;
|
||||
|
@@ -115,12 +115,10 @@ public interface RoomBoomConstant {
|
||||
* 土耳其:普通100%+lucky5%+Bravo2%
|
||||
* 英语区:普通100%+lucky2%+Bravo2%
|
||||
* 英语2区:普通100%+lucky5%+Bravo2%
|
||||
* 独联体:普通礼物100%+幸运礼物4%
|
||||
* @return
|
||||
*/
|
||||
BigDecimal NORMAL_GIFT_BOOM_RATE = BigDecimal.valueOf(1.0D);
|
||||
BigDecimal SUPER_GIFT_BOOM_RATE_AR = BigDecimal.valueOf(0.05D);
|
||||
BigDecimal SUPER_GIFT_BOOM_RATE_SO = BigDecimal.valueOf(0.04D);
|
||||
BigDecimal SUPER_GIFT_BOOM_RATE_EN = BigDecimal.valueOf(0.02D);
|
||||
BigDecimal BRAVO_GIFT_BOOM_RATE_EN = BigDecimal.valueOf(0.02D);
|
||||
|
||||
@@ -129,8 +127,6 @@ public interface RoomBoomConstant {
|
||||
LUCKY((type, partition) -> {
|
||||
if (PartitionEnum.ENGLISH.getId() == partition || PartitionEnum.CHINESE.getId() == partition) {
|
||||
return SUPER_GIFT_BOOM_RATE_EN;
|
||||
} else if (PartitionEnum.SOVIET.getId() == partition) {
|
||||
return SUPER_GIFT_BOOM_RATE_SO;
|
||||
}
|
||||
return SUPER_GIFT_BOOM_RATE_AR;
|
||||
}),
|
||||
|
@@ -64,7 +64,7 @@ public enum GuildWithdrawAccountTypeEnum {
|
||||
SWIFT_CODE("swiftcode", PartitionEnum.ENGLISH2.getId(), List.of(CountryEnum.NG),
|
||||
List.of(GuildWithdrawAccountFieldEnum.COUNTRY, GuildWithdrawAccountFieldEnum.ACCOUNT_NO, GuildWithdrawAccountFieldEnum.ACCOUNT_NAME, GuildWithdrawAccountFieldEnum.SWIFT_CODE)),
|
||||
|
||||
USDT_SOVIET("USDT/Binance/Volet", PartitionEnum.SOVIET.getId(), List.of(CountryEnum.RU,CountryEnum.UZ,CountryEnum.BY,CountryEnum.UA,CountryEnum.KG,CountryEnum.TJ,CountryEnum.TM,
|
||||
USDT_SOVIET("usdt", PartitionEnum.SOVIET.getId(), List.of(CountryEnum.RU,CountryEnum.UZ,CountryEnum.BY,CountryEnum.UA,CountryEnum.KG,CountryEnum.TJ,CountryEnum.TM,
|
||||
CountryEnum.MD,CountryEnum.GE,CountryEnum.AM,CountryEnum.KZ,CountryEnum.Other),
|
||||
List.of(GuildWithdrawAccountFieldEnum.COUNTRY, GuildWithdrawAccountFieldEnum.ACCOUNT)),
|
||||
|
||||
|
@@ -6,7 +6,6 @@ import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@Data
|
||||
public class Lucky24GiftConfig {
|
||||
@@ -64,22 +63,11 @@ public class Lucky24GiftConfig {
|
||||
private BigDecimal storeRatio;
|
||||
private Integer startHour;
|
||||
private Integer endHour;
|
||||
@Deprecated
|
||||
private Integer inputThreshold;
|
||||
@Deprecated
|
||||
private Set<String> userRechargeLevels;
|
||||
@Deprecated
|
||||
private BigDecimal todayProductionRatio;
|
||||
@Deprecated
|
||||
private Long todayDiff;
|
||||
@Deprecated
|
||||
private Integer twoDayCountLimit;
|
||||
|
||||
private Integer dayCountLimit;
|
||||
private List<Integer> timesJudgeArray;
|
||||
// 今天avg(input)-三天内sum(input)-三天内productionRatio-drawMultiple
|
||||
private TreeMap<BigDecimal, TreeMap<Long, TreeMap<BigDecimal, Integer>>> judgeConfig;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,37 +0,0 @@
|
||||
package com.accompany.business.model.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @Author: yangming
|
||||
* @Date: 2020/5/13 20:06
|
||||
* @Description: 页面活动
|
||||
**/
|
||||
@Data
|
||||
@TableName(value = "page_activity")
|
||||
public class PageActivity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id",type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String code;
|
||||
|
||||
private String title;
|
||||
|
||||
private String secondTitle;
|
||||
|
||||
private String imgUrl;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private Date updateTime;
|
||||
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
package com.accompany.business.vo.activities;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author linuxea
|
||||
* @date 2019/9/29 17:54
|
||||
*/
|
||||
@Data
|
||||
public class PageActivityVO {
|
||||
|
||||
/** id 标识 */
|
||||
private Long id;
|
||||
|
||||
/** 活动代码 */
|
||||
private String code;
|
||||
|
||||
/** 活动页面标题 */
|
||||
private String title;
|
||||
|
||||
/** 活动二级标题 */
|
||||
private String secondTitle;
|
||||
|
||||
/** 页面活动图片地址 */
|
||||
private String imgUrl;
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
package com.accompany.business.mybatismapper.activity;
|
||||
|
||||
import com.accompany.business.model.activity.PageActivity;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @Author: yangming
|
||||
* @Date: 2020/5/13 20:14
|
||||
* @Description: 页面活动
|
||||
**/
|
||||
public interface PageActivityMapper extends BaseMapper<PageActivity> {
|
||||
}
|
@@ -2,10 +2,8 @@ package com.accompany.business.mybatismapper.room;
|
||||
|
||||
import com.accompany.business.model.room.RoomBoomSign;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -36,8 +34,4 @@ public interface RoomBoomSignMapper extends BaseMapper<RoomBoomSign> {
|
||||
* @return 开奖情况
|
||||
*/
|
||||
RoomBoomSign getOneByRecordIdAndLevel(@Param("recordId") Long recordId, @Param("level") Integer level);
|
||||
|
||||
IPage<RoomBoomSign> list(@Param("page") IPage<RoomBoomSign> page, @Param("roomUid") Long roomUid, @Param("uid") Long uid,
|
||||
@Param("level") Integer level, @Param("startTime") Date startTime, @Param("endTime") Date endTime,
|
||||
@Param("partitionId") Integer partitionId);
|
||||
}
|
||||
|
@@ -1,49 +0,0 @@
|
||||
package com.accompany.business.service.activity;
|
||||
|
||||
import com.accompany.business.model.activity.PageActivity;
|
||||
import com.accompany.business.mybatismapper.activity.PageActivityMapper;
|
||||
import com.accompany.core.util.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: yangming
|
||||
* @Date: 2020/5/13 20:16
|
||||
* @Description: 页面活动配置
|
||||
**/
|
||||
@Service
|
||||
public class PageActivityService extends ServiceImpl<PageActivityMapper,PageActivity> {
|
||||
|
||||
public PageActivity getByCode(String code){
|
||||
QueryWrapper<PageActivity> wrapper = new QueryWrapper<>();
|
||||
wrapper.lambda().eq(PageActivity::getCode,code)
|
||||
.orderByDesc(PageActivity::getId);
|
||||
List<PageActivity> pageActivities = list(wrapper);
|
||||
if(CollectionUtils.isEmpty(pageActivities)){
|
||||
return null;
|
||||
}
|
||||
return pageActivities.get(0);
|
||||
}
|
||||
|
||||
public IPage<PageActivity> pageList(String searchKey, Integer page, Integer pageSize) {
|
||||
QueryWrapper<PageActivity> wrapper = new QueryWrapper<>();
|
||||
wrapper.lambda().like(StringUtils.isNoneBlank(searchKey),PageActivity::getCode,searchKey).or()
|
||||
.like(StringUtils.isNoneBlank(searchKey),PageActivity::getTitle,searchKey).or()
|
||||
.like(StringUtils.isNoneBlank(searchKey),PageActivity::getSecondTitle,searchKey)
|
||||
.orderByDesc(PageActivity::getId);
|
||||
IPage<PageActivity> iPage = new Page<>(page,pageSize);
|
||||
return page(iPage,wrapper);
|
||||
}
|
||||
|
||||
public long countByCode(String code) {
|
||||
QueryWrapper<PageActivity> wrapper = new QueryWrapper<>();
|
||||
wrapper.lambda().eq(PageActivity::getCode,code);
|
||||
return count(wrapper);
|
||||
}
|
||||
}
|
@@ -102,32 +102,22 @@ public class Lucky24GiftSendService {
|
||||
private Map<Long, Lucky24Record> draw(Lucky24GiftConfig config, Lucky24GiftConfig partitionConfig, long senderUid, Integer partitionId,
|
||||
Gift gift, int everyGiftNum, long everyoneGoldNum,
|
||||
List<Long> receiverList, Room room, Date sendGiftTime, boolean extraSwitch) {
|
||||
if (!extraSwitch
|
||||
|| config.getBlackUidList().contains(senderUid)
|
||||
|| userMetaService.getTimes(senderUid) <= (long) config.getPoolSize() * config.getNewUserPoolCount()){
|
||||
if (!extraSwitch){
|
||||
return draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverList, room, sendGiftTime);
|
||||
}
|
||||
|
||||
Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig = partitionConfig.getExtraPoolConfig();
|
||||
Long extraLuckerUid = extraService.selectExtraLucker(extraPoolConfig, senderUid, partitionId, receiverList);
|
||||
if (null == extraLuckerUid){
|
||||
Long extraLucker = extraService.selectExtraLucker(extraPoolConfig, senderUid, partitionId, everyoneGoldNum, receiverList);
|
||||
if (null == extraLucker){
|
||||
return draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverList, room, sendGiftTime);
|
||||
}
|
||||
|
||||
Integer extraDrawMultiple = extraService.drawMultiple(extraPoolConfig, senderUid, partitionId);
|
||||
if (null == extraDrawMultiple){
|
||||
return draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverList, room, sendGiftTime);
|
||||
}
|
||||
|
||||
Lucky24Record extraRecord = extraService.buildRecord(config, partitionConfig, senderUid, partitionId, extraLuckerUid, gift, everyGiftNum, everyoneGoldNum, room, sendGiftTime, extraDrawMultiple);
|
||||
if (null == extraRecord){
|
||||
return draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverList, room, sendGiftTime);
|
||||
}
|
||||
Lucky24Record extraRecord = extraService.randomExtraRecord(config, senderUid, partitionId, extraLucker, gift, everyGiftNum, everyoneGoldNum, room, sendGiftTime);
|
||||
|
||||
List<Long> receiverUidList = new ArrayList<>(receiverList);
|
||||
receiverUidList.remove(extraLuckerUid);
|
||||
receiverUidList.remove(extraLucker);
|
||||
Map<Long, Lucky24Record> recordMap = draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverUidList, room, sendGiftTime);
|
||||
recordMap.put(extraLuckerUid, extraRecord);
|
||||
recordMap.put(extraLucker, extraRecord);
|
||||
return recordMap;
|
||||
}
|
||||
|
||||
|
@@ -2,9 +2,9 @@ package com.accompany.business.service.lucky;
|
||||
|
||||
import com.accompany.business.constant.Lucky24PoolTypeEnum;
|
||||
import com.accompany.business.dto.lucky.Lucky24GiftConfig;
|
||||
import com.accompany.business.dto.lucky.Lucky24Result;
|
||||
import com.accompany.business.model.Gift;
|
||||
import com.accompany.common.utils.DateTimeUtil;
|
||||
import com.accompany.common.utils.RandomUtil;
|
||||
import com.accompany.core.enumeration.PartitionEnum;
|
||||
import com.accompany.core.model.Room;
|
||||
import com.accompany.payment.service.UserRechargeLevelService;
|
||||
@@ -14,14 +14,13 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RMap;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.*;
|
||||
|
||||
import static com.accompany.business.service.lucky.Lucky24UserMetaService.*;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -30,6 +29,8 @@ public class Lucky24ExtraService {
|
||||
@Autowired
|
||||
private Lucky24ExtraStockService stockService;
|
||||
@Autowired
|
||||
private UserRechargeLevelService userRechargeLevelService;
|
||||
@Autowired
|
||||
private Lucky24UserMetaService userMetaService;
|
||||
@Autowired
|
||||
private Lucky24RobotMsgService robotMsgService;
|
||||
@@ -37,191 +38,102 @@ public class Lucky24ExtraService {
|
||||
private Lucky24SettlementService settlementService;
|
||||
@Autowired
|
||||
private Lucky24RecordService recordService;
|
||||
@Autowired
|
||||
private UserRechargeLevelService userRechargeLevelService;
|
||||
|
||||
public BigDecimal addStock(Integer partitionId, BigDecimal addScore) {
|
||||
return stockService.addStock(partitionId, addScore);
|
||||
}
|
||||
|
||||
public Long selectExtraLucker(Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig, long senderUid, Integer partitionId, List<Long> receiverList) {
|
||||
public Long selectExtraLucker(Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig, long senderUid, Integer partitionId, long everyoneGoldNum, List<Long> receiverList) {
|
||||
PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(partitionId);
|
||||
ZonedDateTime zdt = DateTimeUtil.getDateTimeByZoneId(partitionEnum.getZoneId());
|
||||
if (zdt.getHour() < extraPoolConfig.getStartHour() || zdt.getHour() > extraPoolConfig.getEndHour()){
|
||||
return null;
|
||||
}
|
||||
|
||||
if (everyoneGoldNum < extraPoolConfig.getInputThreshold()){
|
||||
return null;
|
||||
}
|
||||
|
||||
String userRechargeLevel = userRechargeLevelService.getLevelByUid(senderUid);
|
||||
if (!extraPoolConfig.getUserRechargeLevels().contains(userRechargeLevel)){
|
||||
return null;
|
||||
}
|
||||
|
||||
RMap<String, Number> userMetaMap = userMetaService.getUserMeta(senderUid);
|
||||
Map<String, Number> userMetaSnapshot = userMetaMap.readAllMap();
|
||||
long todayStartTimeLong = DateTimeUtil.getZonedTodayTime(partitionEnum.getZoneId());
|
||||
String today = String.valueOf(todayStartTimeLong);
|
||||
String todayInputKey = String.join("_", today, Lucky24UserMetaService.INPUT_KEY);
|
||||
long todayInput = userMetaSnapshot.getOrDefault(todayInputKey, 0L).longValue();
|
||||
String todayOutputKey = String.join("_", today, Lucky24UserMetaService.OUTPUT_KEY);
|
||||
long todayOutput = userMetaSnapshot.getOrDefault(todayOutputKey, 0L).longValue();
|
||||
|
||||
String todayDayCountKey = String.join("_", today, Lucky24UserMetaService.EXTRA_POOL_COUNT);
|
||||
int todayDayCount = userMetaSnapshot.getOrDefault(todayDayCountKey, 0).intValue();
|
||||
if (todayDayCount >= extraPoolConfig.getDayCountLimit()){
|
||||
BigDecimal todayProductionRatio = todayInput > 0L && todayOutput > 0L ? BigDecimal.valueOf(todayOutput).divide(BigDecimal.valueOf(todayInput), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO;
|
||||
if (todayProductionRatio.compareTo(extraPoolConfig.getTodayProductionRatio()) >= 0){
|
||||
log.info("[lucky24] extra todayProductionRation fail uid {} partitionId {} todayInput {} todayOutput {} pr {} configPr {}",
|
||||
senderUid, partitionId, todayInput, todayOutput, todayProductionRatio, extraPoolConfig.getTodayProductionRatio());
|
||||
return null;
|
||||
}
|
||||
|
||||
String todayTimesKey = String.join("_", today, TIMES_KEY);
|
||||
long todayTimes = userMetaSnapshot.getOrDefault(todayTimesKey, 0L).longValue();
|
||||
|
||||
List<Integer> timesJudgeList = extraPoolConfig.getTimesJudgeArray();
|
||||
int maxJudgeTimes = timesJudgeList.get(timesJudgeList.size() - 1);
|
||||
|
||||
Long luckyer = null;
|
||||
|
||||
long todayTimesBefore = todayTimes;
|
||||
for (Long receiver: receiverList){
|
||||
long todayTimesAfter = todayTimesBefore + 1;
|
||||
if (todayTimesBefore < maxJudgeTimes){
|
||||
|
||||
for (Integer judgeTimes: timesJudgeList){
|
||||
if (todayTimesBefore < judgeTimes && todayTimesAfter >= judgeTimes){
|
||||
luckyer = receiver;
|
||||
break;
|
||||
} else if (judgeTimes == maxJudgeTimes && todayTimesAfter >= maxJudgeTimes){
|
||||
long beforeMod = todayTimesBefore / maxJudgeTimes;
|
||||
long afterMod = todayTimesAfter / maxJudgeTimes;
|
||||
if (beforeMod < afterMod){
|
||||
luckyer = receiver;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null != luckyer){
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
long beforeMod = todayTimesBefore / maxJudgeTimes;
|
||||
long afterMod = todayTimesAfter / maxJudgeTimes;
|
||||
if (beforeMod < afterMod){
|
||||
luckyer = receiver;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
todayTimesBefore = todayTimesAfter;
|
||||
}
|
||||
|
||||
if (null == luckyer){
|
||||
long todayDiff = todayInput - todayOutput;
|
||||
if (todayDiff < extraPoolConfig.getTodayDiff()){
|
||||
log.info("[lucky24] extra todayDiff fail uid {} partitionId {} todayInput {} todayOutput {} todayDiff {} configTodayDiff {}",
|
||||
senderUid, partitionId, todayInput, todayOutput, todayDiff, extraPoolConfig.getTodayDiff());
|
||||
return null;
|
||||
}
|
||||
|
||||
// cas 当天剩余额外次数
|
||||
int afterValue = userMetaMap.addAndGet(todayDayCountKey, 1).intValue();
|
||||
if (afterValue > extraPoolConfig.getDayCountLimit()){
|
||||
log.error("[lucky24] extra addAndGet fail uid {} partitionId {} todayDayKey {} afterValue {}", senderUid, partitionId, todayDayCount, afterValue);
|
||||
String yesterday = zdt.minusDays(1L).format(DateTimeUtil.dateFormatter);
|
||||
String lastTwoDayKey = String.join("_", Lucky24UserMetaService.EXTRA_POOL_COUNT, yesterday);
|
||||
int lastTwoDayCount = userMetaSnapshot.getOrDefault(lastTwoDayKey, 0).intValue();
|
||||
if (lastTwoDayCount >= extraPoolConfig.getTwoDayCountLimit()){
|
||||
return null;
|
||||
}
|
||||
|
||||
log.info("[lucky24] extra addAndGet true uid {} partitionId {} todayDayKey {} afterValue {}", senderUid, partitionId, todayDayCount, afterValue);
|
||||
|
||||
return luckyer;
|
||||
int expectedValue = lastTwoDayCount + 1;
|
||||
int result = userMetaMap.compute(lastTwoDayKey, (key, currentVal) -> {
|
||||
if (currentVal == null || currentVal.intValue() == lastTwoDayCount) {
|
||||
return expectedValue;
|
||||
}
|
||||
|
||||
public Integer drawMultiple(Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig, long senderUid, Integer partitionId) {
|
||||
|
||||
Map<String, Number> userMetaMapSnapshot = userMetaService.getUserMeta(senderUid).readAllMap();
|
||||
|
||||
PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(partitionId);
|
||||
long todayStartTimeLong = DateTimeUtil.getZonedTodayTime(partitionEnum.getZoneId());
|
||||
|
||||
String today = String.valueOf(todayStartTimeLong);
|
||||
String todayTimesKey = String.join("_", today, TIMES_KEY);
|
||||
long todayTimes = userMetaMapSnapshot.getOrDefault(todayTimesKey, 0L).longValue();
|
||||
String todayInputKey = String.join("_", today, INPUT_KEY);
|
||||
long todayInput = userMetaMapSnapshot.getOrDefault(todayInputKey, 0L).longValue();
|
||||
String todayOutputKey = String.join("_", today, INPUT_KEY);
|
||||
long todayOutput = userMetaMapSnapshot.getOrDefault(todayOutputKey, 0L).longValue();
|
||||
|
||||
// 第一层
|
||||
// 今天avg(input)
|
||||
BigDecimal todayAvgInput = todayInput <= 0L? BigDecimal.ZERO:
|
||||
BigDecimal.valueOf(todayInput).divide(BigDecimal.valueOf(todayTimes), 4, RoundingMode.HALF_UP);
|
||||
|
||||
// floor返回小于或等于 key 的最大键值对
|
||||
Map.Entry<BigDecimal, TreeMap<Long, TreeMap<BigDecimal, Integer>>> inputJudgeEntry = extraPoolConfig.getJudgeConfig().floorEntry(todayAvgInput);
|
||||
if (null == inputJudgeEntry){
|
||||
return null;
|
||||
}
|
||||
TreeMap<Long, TreeMap<BigDecimal, Integer>> inputJudgeMap = inputJudgeEntry.getValue();
|
||||
if (CollectionUtils.isEmpty(inputJudgeMap)){
|
||||
return currentVal; // 如果当前值不等于期望值,则返回原值,不做修改
|
||||
}).intValue();
|
||||
if (result != expectedValue){
|
||||
log.error("[lucky24] extra cas failure uid {} partitionId {} lastTwoDayKey {} expectedValue {} result {}",
|
||||
senderUid, partitionId, lastTwoDayCount, expectedValue, result);
|
||||
return null;
|
||||
}
|
||||
|
||||
log.info("[lucky24] extra randomExtra first uid {} partitionId {} todayInput {} todayTimes {} todayAvgInput {} ceilingKey {}",
|
||||
senderUid, partitionId, todayInput, todayTimes, todayAvgInput.toPlainString(), inputJudgeEntry.getKey());
|
||||
String todayKey = String.join("_", Lucky24UserMetaService.EXTRA_POOL_COUNT, zdt.format(DateTimeUtil.dateFormatter));
|
||||
int todayAfter = userMetaMap.addAndGet(todayKey, 1).intValue();
|
||||
|
||||
// 第二层
|
||||
// 三天内sum(input)
|
||||
log.error("[lucky24] extra cas success uid {} partitionId {} lastTwoDayKey {} expectedValue {} result {} todayKey {} todayAfter {} lucker {}",
|
||||
senderUid, partitionId, lastTwoDayKey, expectedValue, result, todayKey, todayAfter, receiverList.get(0));
|
||||
|
||||
String twoDayAgoInputKey = String.join("_", INPUT_KEY, TWO_DAY_AGO);
|
||||
long twoDayAgoInput = userMetaMapSnapshot.getOrDefault(twoDayAgoInputKey, 0L).longValue();
|
||||
long threeDayAgoInput = todayInput + twoDayAgoInput;
|
||||
|
||||
// ceiling返回大于或等于 key 的最小键值对
|
||||
Map.Entry<Long, TreeMap<BigDecimal, Integer>> threeDayAgoInputEntry = inputJudgeMap.ceilingEntry(threeDayAgoInput);
|
||||
if (null == threeDayAgoInputEntry){
|
||||
return null;
|
||||
}
|
||||
TreeMap<BigDecimal, Integer> threeDayAgoInputMap = threeDayAgoInputEntry.getValue();
|
||||
if (CollectionUtils.isEmpty(threeDayAgoInputMap)){
|
||||
return null;
|
||||
return receiverList.get(0);
|
||||
}
|
||||
|
||||
log.info("[lucky24] extra randomExtra second uid {} partitionId {} todayInput {} twoDayAgoInput {} threeDayAgoInput {} floorKey {}",
|
||||
senderUid, partitionId, todayInput, twoDayAgoInput, threeDayAgoInput, threeDayAgoInputEntry.getKey());
|
||||
public Lucky24Record randomExtraRecord(Lucky24GiftConfig config, long senderUid, Integer partitionId, Long receiverUid,
|
||||
Gift gift, int giftNum, long everyoneGoldNum, Room room, Date sendGiftTime) {
|
||||
int random = RandomUtil.randomByRange(0, 10);
|
||||
int drawMultiple = random < 5 ? 1000: random < 9 ? 500: 250;
|
||||
|
||||
// 第三层
|
||||
// 三天内productionRation
|
||||
|
||||
String twoDayAgoOutputKey = String.join("_", OUTPUT_KEY, TWO_DAY_AGO);
|
||||
long twoDayAgoOutput = userMetaMapSnapshot.getOrDefault(twoDayAgoOutputKey, 0L).longValue();
|
||||
long threeDayAgoOutput = todayOutput + twoDayAgoOutput;
|
||||
|
||||
BigDecimal threeDayProductionRatio = threeDayAgoOutput <= 0L || threeDayAgoInput <= 0 ? BigDecimal.ZERO:
|
||||
BigDecimal.valueOf(threeDayAgoOutput).divide(BigDecimal.valueOf(threeDayAgoInput), 4, RoundingMode.HALF_UP);
|
||||
|
||||
// floor返回小于或等于 key 的最大键值对
|
||||
Map.Entry<BigDecimal, Integer> threeDayProductionRatioEntry = threeDayAgoInputMap.ceilingEntry(threeDayProductionRatio);
|
||||
Integer drawMultiple = null == threeDayProductionRatioEntry || null == threeDayProductionRatioEntry.getValue()?
|
||||
null: threeDayProductionRatioEntry.getValue();
|
||||
|
||||
log.info("[lucky24] extra randomExtra uid {} partitionId {} todayOutput {} twoDayAgoOutput {} threeDayAgoOutput {} threeDayAgoInput {} productionRation {} floorKey {} result {}",
|
||||
senderUid, partitionId, todayOutput, twoDayAgoOutput, threeDayAgoOutput, threeDayAgoInput, threeDayProductionRatio.toPlainString(), threeDayAgoInputEntry.getKey(), drawMultiple);
|
||||
|
||||
return drawMultiple;
|
||||
}
|
||||
|
||||
public Lucky24Record buildRecord(Lucky24GiftConfig config, Lucky24GiftConfig partitionConfig, long senderUid, Integer partitionId, Long receiverUid,
|
||||
Gift gift, int giftNum, long everyoneGoldNum, Room room, Date sendGiftTime, Integer drawMultiple){
|
||||
long afterMultiple = drawMultiple;
|
||||
|
||||
// 额外平台库存
|
||||
long preWinGoldNum = afterMultiple * everyoneGoldNum;
|
||||
BigDecimal preWinGoldNumDecimal = BigDecimal.valueOf(preWinGoldNum);
|
||||
Lucky24StockResultVo stockResultVo = judgeStock(partitionId, preWinGoldNumDecimal, senderUid, receiverUid, gift, giftNum, everyoneGoldNum, room, sendGiftTime);
|
||||
// 平台库存
|
||||
BigDecimal preWinGoldNum = BigDecimal.valueOf(afterMultiple * everyoneGoldNum);
|
||||
Lucky24StockResultVo stockResultVo = judgeStock(partitionId, preWinGoldNum, senderUid, receiverUid, gift, giftNum, everyoneGoldNum, room, sendGiftTime);
|
||||
if (!stockResultVo.isSuccess()){
|
||||
return null;
|
||||
afterMultiple = 0L;
|
||||
}
|
||||
|
||||
// 个人库存
|
||||
String userRechargeLevel = userRechargeLevelService.getLevelByUid(senderUid);
|
||||
stockResultVo = userMetaService.judgePersonalStock(partitionConfig, senderUid, receiverUid, everyoneGoldNum, userRechargeLevel, afterMultiple, preWinGoldNum);
|
||||
afterMultiple = stockResultVo.getMultiple();
|
||||
|
||||
long winGoldNum = afterMultiple * everyoneGoldNum;
|
||||
|
||||
if (winGoldNum > 0L){
|
||||
settlementService.sendReward(config, senderUid, room, gift, winGoldNum, afterMultiple);
|
||||
}
|
||||
|
||||
userMetaService.updateUserMeta(senderUid, partitionId, everyoneGoldNum, winGoldNum);
|
||||
userMetaService.updateExtraUserMeta(senderUid, partitionId, everyoneGoldNum, winGoldNum);
|
||||
|
||||
log.info("[lucky24] extra uid {} partitionId {} receiverUid {} drawMultiple {} preWinGoldNum {} afterMultiple {} winGoldNum {}",
|
||||
senderUid, partitionId, receiverUid, drawMultiple, preWinGoldNum, afterMultiple, winGoldNum);
|
||||
log.info("[lucky24] extra uid {} partitionId {} receiverUid {} random {} drawMultiple {} preWinGoldNum {} afterMultiple {} winGoldNum {}",
|
||||
senderUid, partitionId, receiverUid, random, drawMultiple, preWinGoldNum, afterMultiple, winGoldNum);
|
||||
|
||||
return recordService.buildRecord(senderUid, partitionId, gift, giftNum, null != room? room.getUid(): null,
|
||||
receiverUid, Lucky24PoolTypeEnum.EXTRA_POOL.getType(), null,
|
||||
@@ -246,5 +158,4 @@ public class Lucky24ExtraService {
|
||||
resultVo.setPreWinGoldNum(winGoldNum);
|
||||
return resultVo;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -17,18 +17,19 @@ import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class Lucky24UserMetaService {
|
||||
|
||||
public static final String TIMES_KEY = "times";
|
||||
private static final String TIMES_KEY = "times";
|
||||
public static final String INPUT_KEY = "input";
|
||||
public static final String OUTPUT_KEY = "output";
|
||||
|
||||
private static final String TODAY = "today";
|
||||
public static final String TWO_DAY_AGO = "two_day_ago";
|
||||
|
||||
public static final String EXTRA_POOL_COUNT = "extra_pool_count";
|
||||
|
||||
@@ -151,15 +152,13 @@ public class Lucky24UserMetaService {
|
||||
long todayStartTimeLong = DateTimeUtil.getZonedTodayTime(partitionEnum.getZoneId());
|
||||
|
||||
String today = String.valueOf(todayStartTimeLong);
|
||||
String todayTimesKey = String.join("_", today, TIMES_KEY);
|
||||
long todayTimes = userMetaMap.addAndGet(todayTimesKey, 1L).longValue();
|
||||
String todayInputKey = String.join("_", today, INPUT_KEY);
|
||||
long todayInput = userMetaMap.addAndGet(todayInputKey, input).longValue();
|
||||
String todayOutputKey = String.join("_", today, OUTPUT_KEY);
|
||||
long todayOutput = userMetaMap.addAndGet(todayOutputKey, output).longValue();
|
||||
|
||||
log.info("[Lucky24] updateExtraUserMeta uid {} times {} today {} todayTime {} todayInput {} todayOutput {}",
|
||||
senderUid, times, todayStartTimeLong, todayTimes, todayInput, todayOutput);
|
||||
log.info("[Lucky24] updateExtraUserMeta uid {} times {} today {} todayInput {} todayOutput {}",
|
||||
senderUid, times, todayStartTimeLong, todayInput, todayOutput);
|
||||
}
|
||||
|
||||
public void updateUserMeta(long senderUid, int partitionId, long input, long output) {
|
||||
@@ -182,8 +181,6 @@ public class Lucky24UserMetaService {
|
||||
long todayStartTimeLong = DateTimeUtil.getZonedTodayTime(partitionEnum.getZoneId());
|
||||
|
||||
String today = String.valueOf(todayStartTimeLong);
|
||||
String todayTimesKey = String.join("_", today, TIMES_KEY);
|
||||
long todayTimes = userMetaMap.addAndGet(todayTimesKey, 1L).longValue();
|
||||
String todayInputKey = String.join("_", today, INPUT_KEY);
|
||||
long todayInput = userMetaMap.addAndGet(todayInputKey, input).longValue();
|
||||
String todayOutputKey = String.join("_", today, OUTPUT_KEY);
|
||||
@@ -192,76 +189,28 @@ public class Lucky24UserMetaService {
|
||||
long userMetaToday = userMetaMap.computeIfAbsent(TODAY, k->todayStartTimeLong).longValue();
|
||||
if (userMetaToday < todayStartTimeLong
|
||||
&& userMetaMap.replace(TODAY, userMetaToday, todayStartTimeLong)){
|
||||
Map<String, Number> userMetaMapSnapshot = userMetaMap.readAllMap();
|
||||
|
||||
// 清理昨天
|
||||
String oldToday = String.valueOf(userMetaToday);
|
||||
String oldTodayTimesKey = String.join("_", oldToday, TIMES_KEY);
|
||||
String oldTodayInputKey = String.join("_", oldToday, INPUT_KEY);
|
||||
String oldTodayOutputKey = String.join("_", oldToday, OUTPUT_KEY);
|
||||
String oldTodayExtraPoolKey = String.join("_", oldToday, EXTRA_POOL_COUNT);
|
||||
userMetaMap.fastRemove(oldTodayInputKey, oldTodayOutputKey);
|
||||
|
||||
int oneDayAgoDiff = 24 * 60 * 60 * 1000;
|
||||
// 清理额外线计数器
|
||||
String todayExtraPoolKey = String.join("_", EXTRA_POOL_COUNT, today);
|
||||
String yesterday = DateTimeUtil.getDateTimeByZoneId(partitionEnum.getZoneId()).minusDays(1L).format(DateTimeUtil.dateFormatter);
|
||||
String yesterdayExtraPoolKey = String.join("_", EXTRA_POOL_COUNT, yesterday);
|
||||
|
||||
if (userMetaToday >= todayStartTimeLong - 2 * oneDayAgoDiff){
|
||||
String oldDayInputKey = String.join("_", INPUT_KEY, oldToday);
|
||||
long oldTodayInput = userMetaMapSnapshot.getOrDefault(oldTodayInputKey, 0L).longValue();
|
||||
|
||||
String oldDayOutputKey = String.join("_", OUTPUT_KEY, oldToday);
|
||||
long oldTodayOutput = userMetaMapSnapshot.getOrDefault(oldTodayOutputKey, 0L).longValue();
|
||||
|
||||
// cache snapshot
|
||||
userMetaMapSnapshot.putAll(Map.of(oldDayInputKey, oldTodayInput, oldDayOutputKey, oldTodayOutput));
|
||||
|
||||
Set<String> needDeleteKeySet = new HashSet<>();
|
||||
for (String key : userMetaMapSnapshot.keySet()){
|
||||
if ((key.startsWith(INPUT_KEY) && !key.equals(INPUT_KEY))
|
||||
|| (key.startsWith(OUTPUT_KEY) && !key.equals(OUTPUT_KEY))){
|
||||
if (key.endsWith(TWO_DAY_AGO)){
|
||||
continue;
|
||||
String extraPoolKeyPattern = EXTRA_POOL_COUNT + "*";
|
||||
Set<String> extraPoolKeySet = userMetaMap.keySet(extraPoolKeyPattern);
|
||||
for (String extraPoolKey : extraPoolKeySet){
|
||||
if (!extraPoolKey.equals(todayExtraPoolKey) && !extraPoolKey.equals(yesterdayExtraPoolKey)){
|
||||
userMetaMap.fastRemove(extraPoolKey);
|
||||
}
|
||||
needDeleteKeySet.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
long twoDayAgoInput = 0L;
|
||||
long twoDayAgoOutput = 0L;
|
||||
|
||||
for (int i = 1; i < 3; i++){
|
||||
long dateStartTimeLong = todayStartTimeLong - i * oneDayAgoDiff;
|
||||
String date = String.valueOf(dateStartTimeLong);
|
||||
|
||||
String dayInputKey = String.join("_", INPUT_KEY, date);
|
||||
long dayInput = userMetaMapSnapshot.getOrDefault(dayInputKey, 0L).longValue();
|
||||
|
||||
needDeleteKeySet.remove(dayInputKey);
|
||||
|
||||
twoDayAgoInput += dayInput;
|
||||
|
||||
String dayOutputKey = String.join("_", OUTPUT_KEY, date);
|
||||
long dayOutput = userMetaMapSnapshot.getOrDefault(dayOutputKey, 0L).longValue();
|
||||
|
||||
needDeleteKeySet.remove(dayOutputKey);
|
||||
|
||||
twoDayAgoOutput += dayOutput;
|
||||
|
||||
}
|
||||
|
||||
String twoDayAgoInputKey = String.join("_", INPUT_KEY, TWO_DAY_AGO);
|
||||
String twoDayAgoOutputKey = String.join("_", OUTPUT_KEY, TWO_DAY_AGO);
|
||||
|
||||
// cache
|
||||
userMetaMap.putAll(Map.of(oldDayInputKey, oldTodayInput, oldDayOutputKey, oldTodayOutput,
|
||||
twoDayAgoInputKey, twoDayAgoInput, twoDayAgoOutputKey, twoDayAgoOutput));
|
||||
|
||||
// clear key
|
||||
needDeleteKeySet.addAll(List.of(oldTodayInputKey, oldTodayOutputKey, oldTodayTimesKey, oldTodayExtraPoolKey));
|
||||
userMetaMap.fastRemove(needDeleteKeySet.toArray(String[]::new));
|
||||
}
|
||||
}
|
||||
|
||||
log.info("[Lucky24] updateUserMeta uid {} times {} todayInput {} todayOutput {} today {} todayTimes {} todayIntput {} todayOutput {}",
|
||||
senderUid, times, totalInput, totalOutput, todayStartTimeLong, todayTimes, todayInput, todayOutput);
|
||||
log.info("[Lucky24] updateUserMeta uid {} times {} today {} todayInput {} todayOutput {}",
|
||||
senderUid, times, todayStartTimeLong, todayInput, todayOutput);
|
||||
}
|
||||
|
||||
public RMap<String, Number> getUserMeta(Long uid) {
|
||||
|
@@ -19,7 +19,7 @@ import com.accompany.business.service.user.UserBackpackService;
|
||||
import com.accompany.business.util.redenvelope.OpenRedEnvelopeUtil;
|
||||
import com.accompany.common.constant.Attach;
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.utils.JsonUtil;
|
||||
import com.accompany.core.util.JsonUtil;
|
||||
import com.accompany.core.base.SpringContextHolder;
|
||||
import com.accompany.core.model.Room;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@@ -16,7 +16,7 @@ import com.accompany.business.service.user.UsersService;
|
||||
import com.accompany.common.constant.Attach;
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.utils.DateTimeUtil;
|
||||
import com.accompany.common.utils.JsonUtil;
|
||||
import com.accompany.core.util.JsonUtil;
|
||||
import com.accompany.core.enumeration.I18nAlertEnum;
|
||||
import com.accompany.core.model.Users;
|
||||
import com.accompany.core.service.partition.PartitionInfoService;
|
||||
|
@@ -17,7 +17,7 @@ import com.accompany.common.constant.Attach;
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.DateTimeUtil;
|
||||
import com.accompany.common.utils.JsonUtil;
|
||||
import com.accompany.core.util.JsonUtil;
|
||||
import com.accompany.core.enumeration.I18nAlertEnum;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Users;
|
||||
|
@@ -208,8 +208,8 @@ public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource> i
|
||||
isSkip = Integer.parseInt(val1) > Integer.parseInt(val2);
|
||||
}
|
||||
} else if (OperateType.GE.name().equals(kind)) {
|
||||
boolean needLimit = RuleCodeEnum.USER_LEVEL.name().equals(key) && limitUserLevel;
|
||||
if (needLimit) {
|
||||
limitUserLevel = RuleCodeEnum.USER_LEVEL.name().equals(key) && limitUserLevel;
|
||||
if (!limitUserLevel) {
|
||||
if (targetValue.toString().contains(StrUtil.DOT) && !targetValue.toString().startsWith(StrUtil.DELIM_START) && !targetValue.toString().startsWith(StrUtil.DELIM_END)){
|
||||
isSkip = AppVersionUtil.compareVersion(val1, val2) < 0;
|
||||
} else {
|
||||
|
@@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil;
|
||||
import com.accompany.business.constant.RoomBoomConstant;
|
||||
import com.accompany.business.dto.room.RoomBoomPrizeMsgDTO;
|
||||
import com.accompany.business.message.GiftMessage;
|
||||
import com.accompany.business.message.SuperLuckyGiftDiamondIncomeMessage;
|
||||
import com.accompany.business.model.room.RoomBoomLevel;
|
||||
import com.accompany.business.model.room.RoomBoomLevelAward;
|
||||
import com.accompany.business.model.room.RoomBoomSign;
|
||||
@@ -26,6 +27,7 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.redisson.api.*;
|
||||
@@ -42,6 +44,7 @@ import org.springframework.util.CollectionUtils;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@@ -1,10 +1,8 @@
|
||||
package com.accompany.business.service.room;
|
||||
|
||||
import com.accompany.business.model.room.RoomBoomSign;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -43,7 +41,5 @@ public interface RoomBoomSignService extends IService<RoomBoomSign> {
|
||||
* @return 记录
|
||||
*/
|
||||
RoomBoomSign getOneByRecordIdAndLevel(Long recordId, Integer level);
|
||||
|
||||
IPage<RoomBoomSign> list(IPage<RoomBoomSign> page, Long roomUid, Long uid, Integer level, Date startTime, Date endTime, Integer partitionId);
|
||||
}
|
||||
|
||||
|
@@ -1,287 +1,2 @@
|
||||
package com.accompany.business.service.room.impl;
|
||||
|
||||
import cn.hutool.core.date.StopWatch;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.accompany.business.constant.GenderEnum;
|
||||
import com.accompany.business.dto.QueueDTO;
|
||||
import com.accompany.business.dto.QueueListResponseDTO;
|
||||
import com.accompany.business.dto.QueueValueDTO;
|
||||
import com.accompany.business.enums.GenderArea;
|
||||
import com.accompany.business.service.room.*;
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.netease.ErBanNetEaseService;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Room;
|
||||
import com.accompany.core.util.JsonUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class BlindDateMaxGiftValueServiceImpl implements BlindDateMaxGiftValueService {
|
||||
|
||||
@Autowired
|
||||
private BlindDateRoundConnectionService blindDateRoundConnectionService;
|
||||
|
||||
@Autowired
|
||||
private QueueService queueService;
|
||||
|
||||
@Autowired
|
||||
private QueryRoomService queryRoomService;
|
||||
|
||||
@Autowired
|
||||
private MicCharmService micCharmService;
|
||||
|
||||
@Autowired
|
||||
private BlindDateCapService blindDateCapService;
|
||||
|
||||
@Autowired
|
||||
private RoomService roomService;
|
||||
|
||||
@Autowired
|
||||
private RoomGiftValueService roomGiftValueService;
|
||||
|
||||
@Autowired
|
||||
private ErBanNetEaseService erBanNetEaseService;
|
||||
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
@Override
|
||||
public void trigger(Long roomUid) {
|
||||
StopWatch stw = new StopWatch("timer");
|
||||
stw.start();
|
||||
log.info("进入了相亲送社触发器");
|
||||
Room roomDTO = roomService.getRoomByUid(roomUid);
|
||||
if (roomDTO == null || roomDTO.getRoomModeType() != Constant.RoomModeType.OPEN_BLIND_DATE_MODE) {
|
||||
log.info("非相亲玩法");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean locked = false;
|
||||
RLock lock = redissonClient.getLock(RedisKey.blind_room_max_gift_val_trigger_lock.getKey(roomUid.toString()));
|
||||
try {
|
||||
locked = lock.tryLock(5, TimeUnit.SECONDS);
|
||||
if (!locked){
|
||||
throw new ServiceException(BusiStatus.SERVERBUSY);
|
||||
}
|
||||
|
||||
long roomId = roomDTO.getRoomId();
|
||||
|
||||
// 发发起魅力值同步
|
||||
roomGiftValueService.pushCurrentGiftValues2Client(roomUid);
|
||||
|
||||
QueueListResponseDTO queueList = queryRoomService.queueList(roomDTO.getRoomId());
|
||||
List<QueueDTO> listDTO = queueList.getDesc().listDTO();
|
||||
|
||||
roomGiftValueService.upMicUpdateVipCache(roomDTO, listDTO);
|
||||
|
||||
log.info("相亲送社触发器" + JsonUtil.parseToString(listDTO));
|
||||
List<Long> micUserIds = listDTO.stream().map(dto -> dto.getValueObject().getUid()).collect(Collectors.toList());
|
||||
|
||||
// 获取到vip席位所在的麦位
|
||||
QueueDTO vipMic = listDTO.stream().filter(dto -> dto.getValueObject().getVipMic()).findFirst().orElse(null);
|
||||
|
||||
int sign = 0;
|
||||
if (vipMic == null) sign = 0;
|
||||
else if (vipMic.getValueObject().getGender() == (byte) 1) sign = 1;
|
||||
else if (vipMic.getValueObject().getGender() == (byte) 2) sign = 2;
|
||||
|
||||
List<Pair<Long, Integer>> positionPair = micUserIds.stream()
|
||||
.map(uid -> new Pair<>(uid, blindDateRoundConnectionService.position(roomId, uid)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("用户与位置关系: " + JsonUtil.parseToString(positionPair));
|
||||
List<Pair<Long, Integer>> boyArea = positionPair.stream().filter(pair -> GenderArea.boyArea.contains(pair.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!boyArea.isEmpty()) {
|
||||
Pair<Long, Integer> maxPairBoy = boyArea.stream()
|
||||
.max(Comparator.comparingLong(pair -> getGiftValue(roomUid, pair.getKey())))
|
||||
.orElseThrow(() -> new ServiceException(BusiStatus.UNEXPECTEDLY_EMPTY));
|
||||
|
||||
if (sign == 1 && GenderArea.vipArea.contains(vipMic.getValueObject().getPosition().intValue())) {
|
||||
dealVipArea(roomUid, vipMic, listDTO, roomId, maxPairBoy, roomDTO, GenderEnum.MALE);
|
||||
} else {
|
||||
updateHatByArea(listDTO, maxPairBoy, roomId, roomDTO, GenderEnum.MALE);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================================
|
||||
List<Pair<Long, Integer>> girlArea = positionPair.stream().filter(pair -> GenderArea.girlArea.contains(pair.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
if (!girlArea.isEmpty()) {
|
||||
Pair<Long, Integer> maxPairGirl = girlArea.stream()
|
||||
.max(Comparator.comparingLong(pair -> getGiftValue(roomUid, pair.getKey())))
|
||||
.orElseThrow(() -> new ServiceException(BusiStatus.UNEXPECTEDLY_EMPTY));
|
||||
|
||||
if (sign == 2 && GenderArea.vipArea.contains(vipMic.getValueObject().getPosition().intValue())) {
|
||||
dealVipArea(roomUid, vipMic, listDTO, roomId, maxPairGirl, roomDTO, GenderEnum.FEMALE);
|
||||
} else {
|
||||
updateHatByArea(listDTO, maxPairGirl, roomId, roomDTO, GenderEnum.FEMALE);
|
||||
}
|
||||
}
|
||||
|
||||
// 主持人区
|
||||
listDTO.stream().filter(dto -> GenderArea.hostArea.contains(dto.getValueObject().getPosition().intValue()))
|
||||
.forEach(dto -> {
|
||||
QueueValueDTO queueValueDTO = dto.getValueObject();
|
||||
// 再次检查
|
||||
queueValueDTO.setVipMic(false);
|
||||
log.info("主持人区当前用户" + queueValueDTO.getUid() + "是vip?" + queueValueDTO.getVipMic());
|
||||
// 主持人区不参与抢帽子
|
||||
queueValueDTO.setCapUrl(null);
|
||||
dto.setRoomid(roomId);
|
||||
dto.setValue(JsonUtil.parseToString(queueValueDTO));
|
||||
queueService.upsert(dto);
|
||||
});
|
||||
|
||||
// vip区防止重新上麦上面的条件不满足没有处理到
|
||||
listDTO.stream().filter(dto -> GenderArea.vipArea.contains(dto.getValueObject().getPosition().intValue()))
|
||||
.forEach(dto -> {
|
||||
QueueValueDTO queueValueDTO = dto.getValueObject();
|
||||
// 再次检查
|
||||
long vipCharmVal = getGiftValue(roomUid, queueValueDTO.getUid());
|
||||
queueValueDTO.setVipMic(roomGiftValueService.checkUserIsVip(queueValueDTO.getUid(), roomDTO));
|
||||
log.info("主持人区当前用户" + queueValueDTO.getUid() + "是vip?" + queueValueDTO.getVipMic());
|
||||
if (queueValueDTO.getGender() == GenderEnum.MALE.getValue() && boyArea.isEmpty() && vipCharmVal > 0) {
|
||||
// 检查帽子
|
||||
queueValueDTO.setCapUrl(blindDateCapService.getByCharmValueAndGender(vipCharmVal, GenderEnum.MALE).getPicUrl());
|
||||
}
|
||||
if (queueValueDTO.getGender() == GenderEnum.FEMALE.getValue() && girlArea.isEmpty() && vipCharmVal > 0) {
|
||||
// 检查帽子
|
||||
queueValueDTO.setCapUrl(blindDateCapService.getByCharmValueAndGender(vipCharmVal, GenderEnum.FEMALE).getPicUrl());
|
||||
}
|
||||
dto.setRoomid(roomId);
|
||||
dto.setValue(JsonUtil.parseToString(queueValueDTO));
|
||||
queueService.upsert(dto);
|
||||
});
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (locked){
|
||||
lock.unlock();
|
||||
}
|
||||
stw.stop();
|
||||
log.info("相亲社触发器执行耗时" + stw.prettyPrint());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void dealVipArea(long roomUid, QueueDTO vipMic, List<QueueDTO> listDTO, long roomId, Pair<Long, Integer> maxPair, Room roomDTO, GenderEnum genderEnum) {
|
||||
long vipCharmVal = getGiftValue(roomUid, vipMic.getValueObject().getUid());
|
||||
long maxGiftValue = getGiftValue(roomUid, maxPair.getKey());
|
||||
List<Integer> area = null;
|
||||
if (genderEnum.equals(GenderEnum.MALE)) area = GenderArea.boyArea;
|
||||
else area = GenderArea.girlArea;
|
||||
log.info("当前vip麦位用户性别[" + genderEnum.getDesc() + "]性别所在区最大魅力值[" + maxGiftValue + "]vip用户魅力值[" + vipCharmVal + "]");
|
||||
if (vipCharmVal >= maxGiftValue) {
|
||||
// 更新队列
|
||||
List<Integer> finalArea = area;
|
||||
listDTO.stream().filter(dto -> finalArea.contains(dto.getValueObject().getPosition().intValue())).forEach(dto -> {
|
||||
QueueValueDTO queueValueDTO = dto.getValueObject();
|
||||
if (queueValueDTO.getCapUrl() != null) {
|
||||
// 再次检查
|
||||
queueValueDTO.setVipMic(roomGiftValueService.checkUserIsVip(queueValueDTO.getUid(), roomDTO));
|
||||
if (queueValueDTO.getVipMic())
|
||||
log.info("触发器1用户" + queueValueDTO.getUid() + "在麦位" + queueValueDTO.getPosition() + "获得vip");
|
||||
queueValueDTO.setCapUrl(null);
|
||||
dto.setRoomid(roomId);
|
||||
dto.setValue(JsonUtil.parseToString(queueValueDTO));
|
||||
queueService.upsert(dto);
|
||||
}
|
||||
});
|
||||
|
||||
vipMic.getValueObject().setCapUrl(blindDateCapService.getByCharmValueAndGender(vipCharmVal, genderEnum).getPicUrl());
|
||||
vipMic.setRoomid(roomId);
|
||||
vipMic.setValue(JsonUtil.parseToString(vipMic.getValueObject()));
|
||||
queueService.upsert(vipMic);
|
||||
log.info("更新 " + vipMic.getValueObject().getUid() + " 的" + genderEnum.getDesc() + "神帽子");
|
||||
} else {
|
||||
vipMic.getValueObject().setCapUrl(null);
|
||||
vipMic.getValueObject().setVipMic(roomGiftValueService.checkUserIsVip(vipMic.getValueObject().getUid(), roomDTO));
|
||||
if (!vipMic.getValueObject().getVipMic()) {
|
||||
// 移除队列
|
||||
log.info("触发器2用户" + vipMic.getValueObject().getUid() + "vip麦位position" + vipMic.getValueObject().getPosition() + "变为false");
|
||||
try {
|
||||
erBanNetEaseService.queuePoll(roomDTO.getRoomId(), vipMic.getValueObject().getPosition().toString());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
vipMic.setRoomid(roomId);
|
||||
vipMic.setValue(JsonUtil.parseToString(vipMic.getValueObject()));
|
||||
queueService.upsert(vipMic);
|
||||
log.info("更新 " + vipMic.getValueObject().getUid() + " 的" + genderEnum.getDesc() + "神帽子");
|
||||
updateHatByArea(listDTO, maxPair, roomId, roomDTO, genderEnum);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(Long roomUid) {
|
||||
log.info("清空 " + roomUid + " 的帽子");
|
||||
Room roomDTO = roomService.getRoomByUid(roomUid);
|
||||
long roomId = roomDTO.getRoomId();
|
||||
QueueListResponseDTO queueList = queryRoomService.queueList(roomId);
|
||||
queueList.getDesc().listDTO().forEach(dto -> {
|
||||
dto.getValueObject().setCapUrl(null);
|
||||
dto.setRoomid(roomId);
|
||||
dto.setValue(JsonUtil.parseToString(dto.getValueObject()));
|
||||
queueService.upsert(dto);
|
||||
});
|
||||
}
|
||||
|
||||
private long getGiftValue(long roomUserId, long userId) {
|
||||
long result = micCharmService.getByRoomUserIdAndUserId(roomUserId, userId);
|
||||
log.info(roomUserId + " 中用户 " + userId + " 的礼物魅力值为 " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void updateHatByArea(List<QueueDTO> listDTO, Pair<Long, Integer> maxPair, long roomId, Room roomDTO, GenderEnum genderEnum) {
|
||||
List<Integer> area = null;
|
||||
if (genderEnum.equals(GenderEnum.MALE)) area = GenderArea.boyArea;
|
||||
else area = GenderArea.girlArea;
|
||||
// 更新队列
|
||||
List<Integer> finalArea = area;
|
||||
listDTO.stream().filter(dto -> finalArea.contains(dto.getValueObject().getPosition().intValue()) && !dto.getValueObject().getPosition().equals(maxPair.getKey()))
|
||||
.forEach(dto -> {
|
||||
QueueValueDTO queueValueDTO = dto.getValueObject();
|
||||
if (queueValueDTO.getCapUrl() != null) {
|
||||
// 检查当前用户是否已经变为vip
|
||||
queueValueDTO.setVipMic(roomGiftValueService.checkUserIsVip(queueValueDTO.getUid(), roomDTO));
|
||||
if (queueValueDTO.getVipMic())
|
||||
log.info("触发器3用户" + queueValueDTO.getUid() + "在麦位" + queueValueDTO.getPosition() + "获得vip");
|
||||
queueValueDTO.setCapUrl(null);
|
||||
dto.setRoomid(roomId);
|
||||
dto.setValue(JsonUtil.parseToString(queueValueDTO));
|
||||
queueService.upsert(dto);
|
||||
}
|
||||
});
|
||||
listDTO.stream().filter(dto -> dto.getValueObject().getPosition().intValue() == maxPair.getValue()).findFirst().ifPresent(dto -> {
|
||||
QueueValueDTO queueValueDTO = dto.getValueObject();
|
||||
// 检查当前用户是否已经变为vip
|
||||
queueValueDTO.setVipMic(roomGiftValueService.checkUserIsVip(queueValueDTO.getUid(), roomDTO));
|
||||
if (queueValueDTO.getVipMic())
|
||||
log.info("触发器4用户" + queueValueDTO.getUid() + "在麦位" + queueValueDTO.getPosition() + "获得vip和帽子");
|
||||
queueValueDTO.setCapUrl(blindDateCapService.getByCharmValueAndGender(getGiftValue(roomDTO.getUid(), maxPair.getKey()), genderEnum).getPicUrl());
|
||||
dto.setRoomid(roomId);
|
||||
dto.setValue(JsonUtil.parseToString(queueValueDTO));
|
||||
queueService.upsert(dto);
|
||||
log.info("更新 " + dto.getValueObject().getUid() + " 的" + genderEnum.getDesc() + "神帽子");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ import com.accompany.common.config.SystemConfig;
|
||||
import com.accompany.common.constant.Attach;
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.utils.BeanUtil;
|
||||
import com.accompany.common.utils.JsonUtil;
|
||||
import com.accompany.core.util.JsonUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@@ -1,569 +1,2 @@
|
||||
package com.accompany.business.service.room.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.accompany.business.constant.GenderEnum;
|
||||
import com.accompany.business.dto.*;
|
||||
import com.accompany.business.dto.blindDate.*;
|
||||
import com.accompany.business.enums.BlindDatePhaseStateEnum;
|
||||
import com.accompany.business.enums.BlindDatePickType;
|
||||
import com.accompany.business.enums.RoomMicPositionType;
|
||||
import com.accompany.business.event.BlindDateNotifyEvent;
|
||||
import com.accompany.business.message.BlindDateNotifyMessage;
|
||||
import com.accompany.business.model.redis.RoomMic;
|
||||
import com.accompany.business.model.room.BlindDateCap;
|
||||
import com.accompany.business.model.room.BlindDateJoinHand;
|
||||
import com.accompany.business.service.room.*;
|
||||
import com.accompany.business.service.user.UsersService;
|
||||
import com.accompany.business.vo.RoomNotifyVo;
|
||||
import com.accompany.business.vo.room.BlindDataConfigVO;
|
||||
import com.accompany.common.config.SystemConfig;
|
||||
import com.accompany.common.constant.Attach;
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.netease.neteaseacc.result.RoomRet;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.UUIDUtil;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Room;
|
||||
import com.accompany.core.model.Users;
|
||||
import com.accompany.core.service.common.JedisService;
|
||||
import com.accompany.core.util.JsonUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.gson.Gson;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class BlindDateServiceImpl implements BlindDateService {
|
||||
|
||||
private final org.slf4j.Logger log = LoggerFactory.getLogger(BlindDateServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private BlindDateRoundConnectionService blindDateRoundConnectionService;
|
||||
|
||||
@Autowired
|
||||
private UsersService userService;
|
||||
|
||||
@Autowired
|
||||
private PushRoomService pushRoomService;
|
||||
|
||||
@Autowired
|
||||
private BlindDateRoundService blindDateRoundService;
|
||||
|
||||
@Autowired
|
||||
private QueryRoomService queryRoomService;
|
||||
|
||||
@Autowired
|
||||
private QueueService queueService;
|
||||
|
||||
@Autowired
|
||||
private BlindDateJoinHandService blindDateJoinHandService;
|
||||
|
||||
@Autowired
|
||||
private MicCharmService micCharmService;
|
||||
|
||||
@Autowired
|
||||
private BlindDateRoundHistoryService blindDateRoundHistoryService;
|
||||
|
||||
@Autowired
|
||||
private RoomService roomService;
|
||||
|
||||
@Autowired
|
||||
private BlindDateMaxGiftValueService blindDateMaxGiftValueService;
|
||||
|
||||
@Autowired
|
||||
private BlindDateRoundConnectionSuccessService blindDateRoundConnectionSuccessService;
|
||||
|
||||
@Autowired
|
||||
private RoomQueueMicroService roomQueueMicroService;
|
||||
|
||||
@Autowired
|
||||
private RoomGiftValueService roomGiftValueService;
|
||||
|
||||
@Autowired
|
||||
private JedisService jedisService;
|
||||
|
||||
@Autowired
|
||||
private IBlindDateCapService iBlindDateCapService;
|
||||
|
||||
@Autowired
|
||||
private IBlindDateJoinHandService iBlindDateJoinHandService;
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
protected Gson gson = new Gson();
|
||||
|
||||
@Override
|
||||
public List<BlindDatePickDTO> matchView(Long roundId) {
|
||||
BlindDateRoundDTO blindDateRoundDTO = blindDateRoundService.getById(roundId);
|
||||
QueueListResponseDTO queueList = queryRoomService.queueList(blindDateRoundDTO.getRoomId());
|
||||
List<QueueDTO> listDTO = queueList.getDesc().listDTO().stream()
|
||||
.filter(dto -> dto.getValueObject().getPosition() != RoomMicPositionType.TOAST_MASTE.getPosition())
|
||||
.collect(Collectors.toList());
|
||||
List<Long> onMicUserId = listDTO.stream()
|
||||
.map(dto -> dto.getValueObject().getUid())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<BlindDatePickDTO> list = blindDateRoundConnectionService.listByRoundId(roundId).stream()
|
||||
.filter(connection -> onMicUserId.contains(connection.getSelectUserId()) &&
|
||||
onMicUserId.contains(connection.getBeSelectedUserId()))
|
||||
.map(connection -> {
|
||||
BlindDatePickDTO blindDatePickDTO = new BlindDatePickDTO();
|
||||
blindDatePickDTO.setOneUserId(connection.getSelectUserId());
|
||||
blindDatePickDTO.setAnotherUserId(connection.getBeSelectedUserId());
|
||||
blindDatePickDTO.setPickType(BlindDatePickType.SINGLE);
|
||||
return blindDatePickDTO;
|
||||
})
|
||||
.collect(Collectors.toCollection(LinkedList::new));
|
||||
|
||||
List<Long> oneUserId = list.stream()
|
||||
.map(BlindDatePickDTO::getOneUserId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<Long> notSelectUserId = onMicUserId.stream()
|
||||
.filter(userId -> !oneUserId.contains(userId))
|
||||
.collect(Collectors.toList());
|
||||
log.info("Users on mic but not selected or being selected: {}", JsonUtil.parseToString(notSelectUserId));
|
||||
List<BlindDatePickDTO> notSelect = notSelectUserId.stream()
|
||||
.map(userId -> {
|
||||
BlindDatePickDTO blindDatePickDTO = new BlindDatePickDTO();
|
||||
blindDatePickDTO.setOneUserId(userId);
|
||||
return blindDatePickDTO;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
list.addAll(notSelect);
|
||||
|
||||
for (BlindDatePickDTO outerBlindDatePickDTO : list) {
|
||||
for (BlindDatePickDTO innerBlindDatePickDTO : list) {
|
||||
if (outerBlindDatePickDTO != null && innerBlindDatePickDTO != null) {
|
||||
if (innerBlindDatePickDTO.getAnotherUserId() != null && outerBlindDatePickDTO.getAnotherUserId() != null && outerBlindDatePickDTO.getAnotherUserId() != null && outerBlindDatePickDTO.getOneUserId() == innerBlindDatePickDTO.getAnotherUserId() &&
|
||||
outerBlindDatePickDTO.getAnotherUserId().equals(innerBlindDatePickDTO.getOneUserId())) {
|
||||
outerBlindDatePickDTO.setPickType(BlindDatePickType.BOTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list.sort((dto1, dto2) -> {
|
||||
int pos1 = listDTO.stream()
|
||||
.filter(dto -> dto.getValueObject().getUid().equals(dto1.getOneUserId()))
|
||||
.findFirst()
|
||||
.map(dto -> dto.getValueObject().getPosition())
|
||||
.orElse(-1L).intValue();
|
||||
int pos2 = listDTO.stream()
|
||||
.filter(dto -> dto.getValueObject().getUid().equals(dto2.getOneUserId()))
|
||||
.findFirst()
|
||||
.map(dto -> dto.getValueObject().getPosition())
|
||||
.orElse(-1L).intValue();
|
||||
return Integer.compare(pos1, pos2);
|
||||
});
|
||||
|
||||
List<BlindDatePickDTO> removeBothWay = new LinkedList<>();
|
||||
LinkedList<BlindDatePickDTO> newLinkedList = new LinkedList<>(list);
|
||||
while (!newLinkedList.isEmpty()) {
|
||||
BlindDatePickDTO pop = newLinkedList.pop();
|
||||
if (removeBothWay.stream().noneMatch(dto -> pop.getAnotherUserId() != null && dto.getAnotherUserId() != null && dto.getOneUserId() == pop.getAnotherUserId() &&
|
||||
dto.getAnotherUserId().equals(pop.getOneUserId()))) {
|
||||
removeBothWay.add(pop);
|
||||
}
|
||||
}
|
||||
|
||||
LinkedList<BlindDatePickDTO> removeBothWay2 = new LinkedList<>(removeBothWay);
|
||||
List<BlindDatePickDTO> linkedList = new LinkedList<>();
|
||||
while (!removeBothWay2.isEmpty()) {
|
||||
BlindDatePickDTO pop = removeBothWay2.pop();
|
||||
if (pop.getPickType() == BlindDatePickType.BOTH) {
|
||||
BlindDatePickDTO first = new BlindDatePickDTO();
|
||||
first.setOneUserId(pop.getOneUserId());
|
||||
first.setAnotherUserId(pop.getAnotherUserId());
|
||||
first.setPickType(BlindDatePickType.SINGLE);
|
||||
|
||||
BlindDatePickDTO two = new BlindDatePickDTO();
|
||||
two.setOneUserId(pop.getAnotherUserId());
|
||||
two.setAnotherUserId(pop.getOneUserId());
|
||||
two.setPickType(BlindDatePickType.SINGLE);
|
||||
|
||||
linkedList.add(first);
|
||||
linkedList.add(two);
|
||||
}
|
||||
linkedList.add(pop);
|
||||
}
|
||||
|
||||
log.info("Matching information for round {}: {}", roundId, JsonUtil.parseToString(linkedList));
|
||||
return linkedList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DatingNotifyInfoDTO> buildNotifyDTO(Long roundId) {
|
||||
BlindDatePhaseStateEnum latestStateByRoundId = blindDateRoundHistoryService.latestStateByRoundId(roundId);
|
||||
List<BlindDatePickDTO> pick = matchView(roundId);
|
||||
BlindDateRoundDTO blindDateRoundDTO = blindDateRoundService.getById(roundId);
|
||||
List<DatingNotifyInfoDTO> list = pick.stream()
|
||||
.map(dto -> {
|
||||
Users oneUser = userService.getUsersByUid(dto.getOneUserId());
|
||||
DatingNotifyInfoDTO datingNotifyInfoDTO = new DatingNotifyInfoDTO();
|
||||
datingNotifyInfoDTO.setHasHeart(dto.getPickType() == BlindDatePickType.BOTH);
|
||||
Long another = dto.getAnotherUserId();
|
||||
Users anotherUser = userService.getUsersByUid(another);
|
||||
if (anotherUser != null) {
|
||||
datingNotifyInfoDTO.setTargetUid(anotherUser.getUid());
|
||||
datingNotifyInfoDTO.setTargetNickname(StrUtil.isNotEmpty(anotherUser.getNick()) ? anotherUser.getNick() : "");
|
||||
Integer position = blindDateRoundConnectionService.position(blindDateRoundDTO.getRoomId(), anotherUser.getUid());
|
||||
datingNotifyInfoDTO.setTargetPosition(position != null ? position : -2);
|
||||
Byte gender = anotherUser.getGender();
|
||||
datingNotifyInfoDTO.setTargetGender(gender != null ? gender : 3);
|
||||
if (datingNotifyInfoDTO.isHasHeart()) {
|
||||
String avatar = anotherUser.getAvatar();
|
||||
datingNotifyInfoDTO.setTargetAvatar(StrUtil.isNotEmpty(avatar) ? avatar : "");
|
||||
}
|
||||
}
|
||||
if (oneUser != null) {
|
||||
datingNotifyInfoDTO.setUid(oneUser.getUid());
|
||||
String oneUserNick = oneUser.getNick();
|
||||
datingNotifyInfoDTO.setNickname(StrUtil.isNotEmpty(oneUserNick) ? oneUserNick : "");
|
||||
Integer position1 = blindDateRoundConnectionService.position(blindDateRoundDTO.getRoomId(), oneUser.getUid());
|
||||
datingNotifyInfoDTO.setPosition(position1 != null ? position1 : -2);
|
||||
Byte gender1 = oneUser.getGender();
|
||||
datingNotifyInfoDTO.setGender(gender1 != null ? gender1 : 3);
|
||||
if (datingNotifyInfoDTO.isHasHeart()) {
|
||||
String avatar = oneUser.getAvatar();
|
||||
datingNotifyInfoDTO.setAvatar(StrUtil.isNotEmpty(avatar) ? avatar : "");
|
||||
}
|
||||
}
|
||||
datingNotifyInfoDTO.setHasSelectUser(dto.getPickType() != null);
|
||||
|
||||
if (dto.getPickType() == BlindDatePickType.BOTH && latestStateByRoundId == BlindDatePhaseStateEnum.PUBLISH) {
|
||||
Room roomDTO = roomService.getRoomByRoomId(blindDateRoundDTO.getRoomId());
|
||||
Long oneUserMicCharmLong = micCharmService.getByRoomUserIdAndUserId(roomDTO.getUid(), dto.getOneUserId());
|
||||
int oneUserMicCharm = 0;
|
||||
if (oneUserMicCharmLong != null) {
|
||||
oneUserMicCharm = oneUserMicCharmLong.intValue();
|
||||
}
|
||||
Long anotherUserMicCharmLong = micCharmService.getByRoomUserIdAndUserId(roomDTO.getUid(), dto.getAnotherUserId());
|
||||
int anotherUserMicCharm = 0;
|
||||
if (anotherUserMicCharmLong != null) {
|
||||
anotherUserMicCharm = anotherUserMicCharmLong.intValue();
|
||||
}
|
||||
int sum = oneUserMicCharm + anotherUserMicCharm;
|
||||
BlindDateJoinHandDTO blindDateJoinHandDTO = blindDateJoinHandService.getByCharmValue((long) sum);
|
||||
log.info("Users [{}] in room [{}] successfully matched, charm value is {}, scene is {}", dto.getOneUserId(), dto.getAnotherUserId(), sum, blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getId() : null);
|
||||
if (datingNotifyInfoDTO.isHasHeart()) {
|
||||
datingNotifyInfoDTO.setSvgaUrl(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getPicUrl() : "");
|
||||
datingNotifyInfoDTO.setSvgaSecond(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getPicSecond() : null);
|
||||
}
|
||||
BlindDateRoundConnectionSuccessDTO blindDateRoundConnectionSuccessDTO = new BlindDateRoundConnectionSuccessDTO();
|
||||
blindDateRoundConnectionSuccessDTO.setBlindDateRoundId(blindDateRoundDTO.getId());
|
||||
blindDateRoundConnectionSuccessDTO.setOneUserId(dto.getOneUserId());
|
||||
blindDateRoundConnectionSuccessDTO.setOneUserGiftValue(oneUserMicCharm);
|
||||
blindDateRoundConnectionSuccessDTO.setAnotherUserId(dto.getAnotherUserId());
|
||||
blindDateRoundConnectionSuccessDTO.setAnotherUserGiftValue(anotherUserMicCharm);
|
||||
blindDateRoundConnectionSuccessDTO.setBlindDateJoinHandUrl(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getPicUrl() : "");
|
||||
blindDateRoundConnectionSuccessDTO.setSvgName(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getTitle() : "");
|
||||
blindDateRoundConnectionSuccessService.create(blindDateRoundConnectionSuccessDTO);
|
||||
if (Constant.status.valid.equals(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getNotifySwitch() : null)) {
|
||||
publishBlindDateNotifyMsg(roomDTO, datingNotifyInfoDTO.getNickname(), datingNotifyInfoDTO.getTargetNickname(), blindDateJoinHandDTO);
|
||||
}
|
||||
if (Constant.BlindRoomDefaultVal.SEND_HEADWEAR_SWITCH_OPEN.equals(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getSendHeadwearSwitch() : null)) {
|
||||
roomGiftValueService.blindDateSendHeadwear(blindDateJoinHandDTO, dto.getOneUserId(), dto.getAnotherUserId());
|
||||
}
|
||||
|
||||
datingNotifyInfoDTO = roomGiftValueService.checkAndExchange(datingNotifyInfoDTO);
|
||||
}
|
||||
return datingNotifyInfoDTO;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("Built notification information for round {}: {}", roundId, JsonUtil.parseToString(list));
|
||||
return list;
|
||||
}
|
||||
|
||||
private void publishBlindDateNotifyMsg(Room room, String oneUserNick, String anotherUserNick, BlindDateJoinHandDTO blindDateJoinHandDTO) {
|
||||
BlindDateNotifyMessage message = new BlindDateNotifyMessage();
|
||||
message.setMessId(UUIDUtil.get());
|
||||
message.setMessTime(System.currentTimeMillis());
|
||||
message.setOneUserNick(oneUserNick);
|
||||
message.setAnotherUserNick(anotherUserNick);
|
||||
message.setRoomUid(room.getUid());
|
||||
message.setRoomTitle(room.getTitle());
|
||||
message.setJoinHandLevel(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getLevel() : null);
|
||||
message.setJoinHandName(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getTitle() : null);
|
||||
message.setBackgroundUrl(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getNotifyBackgroundUrl() : null);
|
||||
message.setSweetWords(blindDateJoinHandDTO != null ? blindDateJoinHandDTO.getSweetWords() : null);
|
||||
try {
|
||||
applicationContext.publishEvent(new BlindDateNotifyEvent(message));
|
||||
} catch (Exception e) {
|
||||
log.error("publishBlindDateNotifyMsg error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(Long roundId) {
|
||||
notifyRound(roundId);
|
||||
}
|
||||
|
||||
private void notifyRound(long roundId) {
|
||||
BlindDateRoundDTO blindDateRoundDTO = blindDateRoundService.getById(roundId);
|
||||
List<DatingNotifyInfoDTO> notifyDTOs = buildNotifyDTO(roundId);
|
||||
if (notifyDTOs.isEmpty()) {
|
||||
log.info("No one participated in this blind date, not sending messages to the client.");
|
||||
return;
|
||||
}
|
||||
Attach attach = new Attach();
|
||||
SendRoomMsgTemplate sendRoomMsgTemplate = new SendRoomMsgTemplate();
|
||||
sendRoomMsgTemplate.setFromUserId(Long.parseLong(SystemConfig.systemMessageUid));
|
||||
sendRoomMsgTemplate.setToRoomId(blindDateRoundDTO.getRoomId());
|
||||
attach.setData(new ListWrapperDTO<>(notifyDTOs));
|
||||
attach.setFirst(Constant.DefineProtocol.CUSTOM_MSG_DATING);
|
||||
attach.setSecond(Constant.DefineProtocol.CUSTOM_MSG_SUB_DATING_PUBLISH_RESULT);
|
||||
sendRoomMsgTemplate.setAttach(JsonUtil.parseToString(attach));
|
||||
pushRoomService.sendRoomMsg(sendRoomMsgTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanQueue(Long roundId) {
|
||||
// 队列还原
|
||||
BlindDateRoundDTO blindDateRoundDTO = blindDateRoundService.getById(roundId);
|
||||
long roomId = blindDateRoundDTO.getRoomId();
|
||||
QueueListResponseDTO queueList = queryRoomService.queueList(roomId);
|
||||
List<QueueDTO> listDTO = queueList.getDesc().listDTO();
|
||||
for (QueueDTO dto : listDTO) {
|
||||
QueueValueDTO valueObject = dto.getValueObject();
|
||||
valueObject.setCapUrl(null);
|
||||
valueObject.setHasSelectUser(null);
|
||||
valueObject.setSelectMicPosition(null);
|
||||
dto.setRoomid(roomId);
|
||||
dto.setValue(JsonUtil.parseToString(valueObject));
|
||||
queueService.upsert(dto);
|
||||
log.info("清空" + roomId + "的相亲坑位信息");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildQueue(Long roundId) {
|
||||
List<BlindDatePickDTO> matchView = matchView(roundId);
|
||||
BlindDateRoundDTO blindDateRoundDTO = blindDateRoundService.getById(roundId);
|
||||
QueueListResponseDTO queueList = queryRoomService.queueList(blindDateRoundDTO.getRoomId());
|
||||
List<QueueDTO> listDTO = queueList.getDesc().listDTO();
|
||||
for (QueueDTO dto : listDTO) {
|
||||
QueueValueDTO valueObject = dto.getValueObject();
|
||||
BlindDatePickDTO myMatchView = matchView.stream()
|
||||
.filter(match -> match.getOneUserId() == valueObject.getUid() &&
|
||||
(match.getPickType() == BlindDatePickType.SINGLE || match.getPickType() == BlindDatePickType.BOTH))
|
||||
.findFirst().orElse(null);
|
||||
if (myMatchView != null) {
|
||||
valueObject.setSelectMicPosition(blindDateRoundConnectionService.position(blindDateRoundDTO.getRoomId(), myMatchView.getAnotherUserId()).toString());
|
||||
valueObject.setHasSelectUser(true);
|
||||
} else {
|
||||
valueObject.setSelectMicPosition(null);
|
||||
valueObject.setHasSelectUser(false);
|
||||
}
|
||||
dto.setValue(JsonUtil.parseToString(valueObject));
|
||||
dto.setRoomid(blindDateRoundDTO.getRoomId());
|
||||
queueService.upsert(dto);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disConnect(Long roundId, Long userId, Long position) {
|
||||
BlindDateRoundDTO blindDateRoundDTO = blindDateRoundService.getById(roundId);
|
||||
long roomId = blindDateRoundDTO.getRoomId();
|
||||
log.info(userId + " " + position + " 在 " + roundId + " 下麦了");
|
||||
|
||||
// Delete information related to the user's selections
|
||||
blindDateRoundConnectionService.deleteBySelectUserId(roundId, userId);
|
||||
// Delete information related to the user being selected
|
||||
blindDateRoundConnectionService.deleteByBeSelectUserId(roundId, userId);
|
||||
// Update the queue
|
||||
buildQueue(roundId);
|
||||
// Trigger the calculation of the highest hat value
|
||||
blindDateMaxGiftValueService.trigger(roomService.getRoomByRoomId(roomId).getUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBlindDateInfo(Long roomUid, boolean isOpen) {
|
||||
Room roomByUserId = roomService.getRoomByUid(roomUid);
|
||||
int posStatus = 1;
|
||||
BlindDateRoundDTO latestByRoomId = null;
|
||||
if (isOpen) {
|
||||
Integer[] modeTypeList = {Constant.RoomModeType.NORMAL_MODE, Constant.RoomModeType.CLOSE_PK_MODE, Constant.RoomModeType.OPEN_MICRO_MODE, Constant.RoomModeType.CLOSE_MICRO_MODE};
|
||||
if (!Arrays.asList(modeTypeList).contains(roomByUserId.getRoomModeType())) {
|
||||
throw new ServiceException(BusiStatus.THE_CURRENT_ROOM_MODE_CANNOT_ENABLE_BLIND_DATES);
|
||||
}
|
||||
|
||||
// 创建新的一轮相亲
|
||||
BlindDateRoundDTO blindDateRoundDTO = new BlindDateRoundDTO();
|
||||
blindDateRoundDTO.setRoomId(roomByUserId.getRoomId());
|
||||
blindDateRoundService.create(blindDateRoundDTO);
|
||||
latestByRoomId = blindDateRoundService.latestByRoomId(roomByUserId.getRoomId());
|
||||
BlindDatePhaseStateEnum currentRoomState = blindDateRoundService.currentRoomState(roomByUserId.getRoomId());
|
||||
// 新增阶段轮次记录
|
||||
BlindDateRoundHistoryDTO blindDateRoundHistoryDTO = new BlindDateRoundHistoryDTO();
|
||||
blindDateRoundHistoryDTO.setBlindDateRoundId(latestByRoomId.getId());
|
||||
blindDateRoundHistoryDTO.setState(currentRoomState);
|
||||
blindDateRoundHistoryDTO.setRoomId(roomByUserId.getRoomId());
|
||||
blindDateRoundHistoryService.create(blindDateRoundHistoryDTO);
|
||||
roomByUserId.setBlindDateState(currentRoomState.getCode());
|
||||
roomByUserId.setRoomModeType(Constant.RoomModeType.OPEN_BLIND_DATE_MODE);
|
||||
// 打开礼物魅力值
|
||||
if (!roomByUserId.getShowGiftValue()) {
|
||||
roomByUserId.setShowGiftValue(true);
|
||||
}
|
||||
// 发房间公屏
|
||||
if (BlindDatePhaseStateEnum.COMMUNICATING.getTip() != null) {
|
||||
SendRoomMsgTemplate sendRoomMsgTemplate = new SendRoomMsgTemplate();
|
||||
sendRoomMsgTemplate.setFromUserId(Long.parseLong(SystemConfig.systemMessageUid));
|
||||
sendRoomMsgTemplate.setToRoomId(roomByUserId.getRoomId());
|
||||
sendRoomMsgTemplate.setAttach(BlindDatePhaseStateEnum.COMMUNICATING.getTip());
|
||||
pushRoomService.sendTip(sendRoomMsgTemplate);
|
||||
}
|
||||
// 清空魅力值
|
||||
try {
|
||||
roomGiftValueService.cleanGiftValueCache(roomUid);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
latestByRoomId = blindDateRoundService.latestByRoomId(roomByUserId.getRoomId());
|
||||
roomByUserId.setBlindDateState(BlindDatePhaseStateEnum.CLOSED.getCode());
|
||||
roomByUserId.setRoomModeType(Constant.RoomModeType.NORMAL_MODE);
|
||||
}
|
||||
// 更新数据库房间信息
|
||||
roomService.updateDbAndCacheRoomInfo(roomByUserId);
|
||||
if (roomByUserId.getBlindDateVipUid() != 0L) {
|
||||
roomByUserId.setBlindDateVipUid(0L);
|
||||
roomService.updateBlindDateVipUid(0L, roomByUserId);
|
||||
|
||||
Room endRoom = roomService.getRoomByUid(roomUid);
|
||||
RoomNotifyVo roomNotifyVo = new RoomNotifyVo();
|
||||
roomNotifyVo.setRoomInfo(gson.toJson(endRoom));
|
||||
roomNotifyVo.setType(Constant.RoomMic.ROOM_NOTIFY_TYPE_ROOM);
|
||||
try {
|
||||
roomService.updateNetEaseRoomInfo(endRoom, gson.toJson(roomNotifyVo));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOpen) {
|
||||
roomGiftValueService.cleanRoomRoundSendGiftVal(roomByUserId.getUid(), latestByRoomId != null ? latestByRoomId.getId() : null);
|
||||
}
|
||||
//更新麦序信息到缓存
|
||||
List<RoomMic> micInfo = roomQueueMicroService.queueBatchUpdate(roomByUserId, posStatus);
|
||||
RoomNotifyVo roomNotifyVo = new RoomNotifyVo();
|
||||
roomNotifyVo.setRoomInfo(gson.toJson(roomByUserId));
|
||||
roomNotifyVo.setMicInfo(gson.toJson(micInfo));
|
||||
roomNotifyVo.setType(Constant.RoomMic.ROOM_NOTIFY_TYPE_ROOM_MIC);
|
||||
//通知云信更新聊天室信息
|
||||
RoomRet roomRet = null;
|
||||
try {
|
||||
roomRet = roomService.updateNetEaseRoomInfo(roomByUserId, JSON.toJSONString(roomNotifyVo));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (roomRet.getCode() == 200) {
|
||||
// 清除队列中有关相亲的信息
|
||||
if (latestByRoomId != null) {
|
||||
cleanQueue(latestByRoomId.getId());
|
||||
}
|
||||
roomGiftValueService.pushCurrentGiftValues2Client(roomUid);
|
||||
// 清除房间排麦队列
|
||||
jedisService.hdel(RedisKey.room_mic_queue.getKey(), Long.toString(roomUid));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlindDataConfigVO getBlindDataConfig() {
|
||||
BlindDataConfigVO blindDataConfigVO = new BlindDataConfigVO();
|
||||
List<BlindDateCap> capList = iBlindDateCapService.list();
|
||||
List<BlindDateCap> femaleCapList = new ArrayList<>();
|
||||
List<BlindDateCap> maleCapList = new ArrayList<>();
|
||||
if (capList != null && !capList.isEmpty()) {
|
||||
for (BlindDateCap cap : capList) {
|
||||
if (cap.getGender() == GenderEnum.MALE) {
|
||||
maleCapList.add(cap);
|
||||
} else {
|
||||
femaleCapList.add(cap);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<BlindDateJoinHand> joinHandList = iBlindDateJoinHandService.listBlindDateJoinHandWithOutDefault();
|
||||
blindDataConfigVO.setFemaleCapList(femaleCapList);
|
||||
blindDataConfigVO.setMaleCapList(maleCapList);
|
||||
blindDataConfigVO.setJoinHandList(joinHandList);
|
||||
return blindDataConfigVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testAA() {
|
||||
List<BlindDatePickDTO> list = new ArrayList<>();
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
BlindDatePickDTO blindDatePickDTO = new BlindDatePickDTO();
|
||||
blindDatePickDTO.setOneUserId((long) i);
|
||||
if (!(i == 5 || i == 6)) blindDatePickDTO.setAnotherUserId((long) (i + 10));
|
||||
// 默认单选
|
||||
blindDatePickDTO.setPickType(BlindDatePickType.SINGLE);
|
||||
list.add(blindDatePickDTO);
|
||||
}
|
||||
|
||||
for (int i = 11; i <= 20; i++) {
|
||||
BlindDatePickDTO blindDatePickDTO = new BlindDatePickDTO();
|
||||
blindDatePickDTO.setOneUserId((long) i);
|
||||
blindDatePickDTO.setAnotherUserId((long) (i - 10));
|
||||
// 默认单选
|
||||
blindDatePickDTO.setPickType(BlindDatePickType.SINGLE);
|
||||
list.add(blindDatePickDTO);
|
||||
}
|
||||
|
||||
// 2.查看是否有双选
|
||||
for (BlindDatePickDTO outerBlindDatePickDTO : list) {
|
||||
for (BlindDatePickDTO innerBlindDatePickDTO : list) {
|
||||
if (innerBlindDatePickDTO.getAnotherUserId() != null && outerBlindDatePickDTO.getAnotherUserId() != null && Objects.equals(outerBlindDatePickDTO.getOneUserId(), innerBlindDatePickDTO.getAnotherUserId()) &&
|
||||
Objects.equals(outerBlindDatePickDTO.getAnotherUserId(), innerBlindDatePickDTO.getOneUserId())) {
|
||||
outerBlindDatePickDTO.setPickType(BlindDatePickType.BOTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4.去除双向选择
|
||||
LinkedList<BlindDatePickDTO> newLinkedList = new LinkedList<>(list);
|
||||
List<BlindDatePickDTO> removeBothWay = new ArrayList<>();
|
||||
while (!newLinkedList.isEmpty()) {
|
||||
BlindDatePickDTO pop = newLinkedList.pop();
|
||||
if (removeBothWay.stream().noneMatch(it -> it.getAnotherUserId() != null && pop.getAnotherUserId() != null && Objects.equals(it.getOneUserId(), pop.getAnotherUserId()) && Objects.equals(it.getAnotherUserId(), pop.getOneUserId()))) {
|
||||
removeBothWay.add(pop);
|
||||
}
|
||||
}
|
||||
|
||||
//5.添加多余信息
|
||||
LinkedList<BlindDatePickDTO> removeBothWay2 = new LinkedList<>(removeBothWay);
|
||||
List<BlindDatePickDTO> linkedList = new ArrayList<>();
|
||||
while (!removeBothWay2.isEmpty()) {
|
||||
BlindDatePickDTO pop = removeBothWay2.pop();
|
||||
if (pop.getPickType() == BlindDatePickType.BOTH) {
|
||||
// 添加两条互相选择的实体
|
||||
BlindDatePickDTO first = new BlindDatePickDTO();
|
||||
first.setOneUserId(pop.getOneUserId());
|
||||
first.setAnotherUserId(pop.getAnotherUserId());
|
||||
first.setPickType(BlindDatePickType.SINGLE);
|
||||
|
||||
BlindDatePickDTO two = new BlindDatePickDTO();
|
||||
two.setOneUserId(pop.getAnotherUserId());
|
||||
two.setAnotherUserId(pop.getOneUserId());
|
||||
two.setPickType(BlindDatePickType.SINGLE);
|
||||
|
||||
linkedList.add(first);
|
||||
linkedList.add(two);
|
||||
}
|
||||
linkedList.add(pop);
|
||||
}
|
||||
|
||||
log.info("配对信息" + JsonUtil.parseToString(linkedList));
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@ import com.accompany.core.model.Users;
|
||||
import com.accompany.core.util.I18NMessageSourceUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RList;
|
||||
@@ -383,11 +382,6 @@ public class RoomBoomSignServiceImpl extends ServiceImpl<RoomBoomSignMapper, Roo
|
||||
return roomBoomSignMapper.getOneByRecordIdAndLevel(recordId, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<RoomBoomSign> list(IPage<RoomBoomSign> page, Long roomUid, Long uid, Integer level, Date startTime, Date endTime, Integer partitionId) {
|
||||
return baseMapper.list(page, roomUid, uid, level, startTime, endTime, partitionId);
|
||||
}
|
||||
|
||||
private void sendAward(RoomBoomLevelAward award, Long uid, Long roomUid) {
|
||||
try {
|
||||
RewardDto rewardDto = new RewardDto();
|
||||
|
@@ -33,32 +33,4 @@
|
||||
select * from room_boom_sign where record_id = #{recordId} and level = #{level} order by id limit 1
|
||||
</select>
|
||||
|
||||
<select id="list" resultType="com.accompany.business.model.room.RoomBoomSign">
|
||||
select r.*
|
||||
from room_boom_sign r
|
||||
left join users u on u.uid = r.room_uid
|
||||
<where>
|
||||
<if test="startTime != null">
|
||||
and r.create_time >= #{startTime}
|
||||
</if>
|
||||
<if test="endTime != null">
|
||||
and r.create_time <= #{endTime}
|
||||
</if>
|
||||
<if test="partitionId != null">
|
||||
and u.partition_id = #{partitionId}
|
||||
</if>
|
||||
<if test="level != null">
|
||||
and r.level = #{level}
|
||||
</if>
|
||||
<if test="roomUid != null">
|
||||
and r.room_uid = #{roomUid}
|
||||
</if>
|
||||
<if test="uid != null">
|
||||
and r.uid = #{uid}
|
||||
</if>
|
||||
and r.`status` = 2
|
||||
</where>
|
||||
order by r.id desc
|
||||
</select>
|
||||
|
||||
</mapper>
|
@@ -30,11 +30,6 @@ public class WebMVCConfig implements WebMvcConfigurer {
|
||||
return new ModelHallAuthInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebInterceptor getWebInterceptor() {
|
||||
return new WebInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public XssInterceptor getXssInterceptor() {
|
||||
return new XssInterceptor();
|
||||
@@ -55,7 +50,6 @@ public class WebMVCConfig implements WebMvcConfigurer {
|
||||
registry.addInterceptor(getLoginInterceptor()).addPathPatterns("/**");
|
||||
//registry.addInterceptor(getAppVersionInterceptor());
|
||||
registry.addInterceptor(getModelHallAuthInterceptor());
|
||||
registry.addInterceptor(getWebInterceptor());
|
||||
registry.addInterceptor(getXssInterceptor());
|
||||
}
|
||||
|
||||
|
@@ -1,39 +0,0 @@
|
||||
package com.accompany.business.controller.activities;
|
||||
|
||||
import com.accompany.business.model.activity.PageActivity;
|
||||
import com.accompany.business.service.activity.PageActivityService;
|
||||
import com.accompany.business.vo.activities.PageActivityVO;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.core.util.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 页面静态活动
|
||||
*
|
||||
* @author linuxea
|
||||
* @date 2019/9/29 17:44
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/page/static/activity")
|
||||
public class PageActivityController {
|
||||
|
||||
@Autowired
|
||||
private PageActivityService pageActivityService;
|
||||
|
||||
/**
|
||||
* 通过活动标识 code 获取
|
||||
*
|
||||
* @param code 活动标识
|
||||
* @return {@link PageActivityVO}
|
||||
*/
|
||||
@GetMapping("/{code}")
|
||||
public BusiResult<PageActivityVO> getByCode(@PathVariable("code") String code) {
|
||||
PageActivity pageActivity = pageActivityService.getByCode(code);
|
||||
PageActivityVO pageActivityVO = BeanUtils.map(pageActivity, PageActivityVO.class);
|
||||
return new BusiResult<>(pageActivityVO);
|
||||
}
|
||||
}
|
@@ -4,7 +4,6 @@ import com.accompany.business.common.BaseController;
|
||||
import com.accompany.business.service.exchange.GoldExchangeDiamondService;
|
||||
import com.accompany.business.vo.exchange.GoldExchangeDiamondVo;
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.annotation.H5Authorization;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
@@ -29,7 +28,6 @@ public class GoldExchangeDiamondController extends BaseController {
|
||||
private GoldExchangeDiamondService service;
|
||||
|
||||
@Authorization
|
||||
@H5Authorization
|
||||
@ApiOperation("获取配置")
|
||||
@GetMapping(value = "/getConfig")
|
||||
public BusiResult<GoldExchangeDiamondVo> getConfig(HttpServletRequest request) {
|
||||
@@ -39,7 +37,6 @@ public class GoldExchangeDiamondController extends BaseController {
|
||||
}
|
||||
|
||||
@Authorization
|
||||
@H5Authorization
|
||||
@ApiOperation("兑换")
|
||||
@PostMapping(value = "/exchange")
|
||||
public BusiResult<Void> exchange(HttpServletRequest request, Long goldNum, Long diamondNum) {
|
||||
|
@@ -6,7 +6,6 @@ import com.accompany.core.enumeration.BillObjTypeEnum;
|
||||
import com.accompany.core.enumeration.BillTypeEnum;
|
||||
import com.accompany.sharding.vo.BillRecordDateVo;
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.annotation.H5Authorization;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.enumeration.CurrencyEnum;
|
||||
|
@@ -6,7 +6,6 @@ import com.accompany.business.service.room.RoomRevenueService;
|
||||
import com.accompany.business.service.room.RoomService;
|
||||
import com.accompany.business.service.user.UsersService;
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.annotation.H5Authorization;
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
@@ -44,7 +43,6 @@ public class RoomRevenueController extends BaseController {
|
||||
@ApiOperation("获取本周牌照房流水")
|
||||
@GetMapping(value = "/weekTotal")
|
||||
@Authorization
|
||||
@H5Authorization
|
||||
public BusiResult weekTotalRevenue() {
|
||||
Long uid = getUid();
|
||||
logger.info("weekTotalRevenue, uid:{}", uid);
|
||||
@@ -54,7 +52,6 @@ public class RoomRevenueController extends BaseController {
|
||||
@ApiOperation("生成本周牌照房流水excel下载链接")
|
||||
@GetMapping(value = "/exportExcel")
|
||||
@Authorization
|
||||
@H5Authorization
|
||||
public BusiResult exportExcel(@RequestParam("start") String start, @RequestParam("end") String end, @RequestParam(value="erbanNo", required = false) Long erbanNo) throws Exception {
|
||||
Long uid = getUid();
|
||||
if (erbanNo != null) {
|
||||
@@ -80,7 +77,6 @@ public class RoomRevenueController extends BaseController {
|
||||
@ApiOperation("获取本周个播房流水")
|
||||
@GetMapping(value = "/singleBroadcast/weekTotal")
|
||||
@Authorization
|
||||
@H5Authorization
|
||||
public BusiResult SingleBroadcastweekTotalRevenue() {
|
||||
Long uid = getUid();
|
||||
logger.info("singleBroadcast weekTotalRevenue, uid:{}", uid);
|
||||
@@ -90,7 +86,6 @@ public class RoomRevenueController extends BaseController {
|
||||
@ApiOperation("生成本周个播房流水excel下载链接")
|
||||
@GetMapping(value = "/singleroom/exportExcel")
|
||||
@Authorization
|
||||
@H5Authorization
|
||||
public BusiResult singleroomExportExcel(@RequestParam("start") String start, @RequestParam("end") String end) throws Exception {
|
||||
Long uid = getUid();
|
||||
logger.info("singleroomExportExcel, uid:{}, start:{}, end:{}", uid, start, end);
|
||||
|
@@ -5,7 +5,6 @@ import com.accompany.business.service.purse.DiamondGiveHistoryService;
|
||||
import com.accompany.business.vo.DiamondGiveHistoryPageVo;
|
||||
import com.accompany.business.vo.SimpleUserVo;
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.annotation.H5Authorization;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
@@ -33,7 +32,6 @@ public class DiamondGiveHistoryController extends BaseController {
|
||||
private DiamondGiveHistoryService diamondGiveHistoryService;
|
||||
|
||||
|
||||
@H5Authorization
|
||||
@Authorization
|
||||
@ApiOperation(value = "用户转赠记录", httpMethod = "GET")
|
||||
@GetMapping("/giveRecord")
|
||||
@@ -50,7 +48,6 @@ public class DiamondGiveHistoryController extends BaseController {
|
||||
* @param pageSize
|
||||
* @return
|
||||
*/
|
||||
@H5Authorization
|
||||
@Authorization
|
||||
@ApiOperation(value = "用户转赠详情记录", httpMethod = "GET")
|
||||
@GetMapping("/giveRecordVoByType")
|
||||
@@ -60,7 +57,6 @@ public class DiamondGiveHistoryController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
@H5Authorization
|
||||
@Authorization
|
||||
@ApiOperation(value = "用户转赠钻石操作", httpMethod = "POST")
|
||||
@PostMapping("/give")
|
||||
@@ -70,7 +66,6 @@ public class DiamondGiveHistoryController extends BaseController {
|
||||
return new BusiResult(BusiStatus.SUCCESS);
|
||||
}
|
||||
|
||||
@H5Authorization
|
||||
@Authorization
|
||||
@ApiOperation(value = "用户转赠礼物操作", httpMethod = "POST")
|
||||
@PostMapping("/giveGift")
|
||||
@@ -83,7 +78,6 @@ public class DiamondGiveHistoryController extends BaseController {
|
||||
|
||||
@ApiOperation(value = "转赠钻石/礼物 -> 用户搜索", httpMethod = "POST")
|
||||
@Authorization
|
||||
@H5Authorization
|
||||
@PostMapping("/searchUser")
|
||||
public BusiResult<SimpleUserVo> searchUser(Long erbanNo) {
|
||||
Long uid = this.getUid();
|
||||
@@ -93,7 +87,6 @@ public class DiamondGiveHistoryController extends BaseController {
|
||||
return new BusiResult<>(diamondGiveHistoryService.searchUser(uid, erbanNo));
|
||||
}
|
||||
|
||||
@H5Authorization
|
||||
@Authorization
|
||||
@ApiOperation(value = "用户转赠历史", httpMethod = "GET")
|
||||
@ApiImplicitParams({
|
||||
|
@@ -5,7 +5,6 @@ import com.accompany.business.service.purse.UserPurseService;
|
||||
import com.accompany.business.vo.UserPurseVo;
|
||||
import com.accompany.business.vo.UserPurseWithRoomTypeVo;
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.annotation.H5Authorization;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -24,7 +23,6 @@ public class UserPurseController extends BaseController {
|
||||
private UserPurseService userPurseService;
|
||||
|
||||
@GetMapping({"query", "query2"})
|
||||
@H5Authorization
|
||||
@Authorization
|
||||
public BusiResult<UserPurseVo> queryMyUserPurse(HttpServletRequest request){
|
||||
Long uid = getUid(request);
|
||||
@@ -36,7 +34,6 @@ public class UserPurseController extends BaseController {
|
||||
}
|
||||
|
||||
@GetMapping("queryWithRoomType")
|
||||
@H5Authorization
|
||||
@Authorization
|
||||
public BusiResult<UserPurseWithRoomTypeVo> queryMyUserPurseWithRoomType(HttpServletRequest request){
|
||||
Long uid = getUid(request);
|
||||
|
@@ -69,19 +69,6 @@ public abstract class BasicInterceptor implements HandlerInterceptor {
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取@H5Authorization注解需要的h5_token
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public String getH5Token(HttpServletRequest request) {
|
||||
String token = request.getHeader(ApplicationConstant.PublicParameters.H5_TOKEN);
|
||||
if (StringUtils.isBlank(token)) {
|
||||
token = request.getParameter(ApplicationConstant.PublicParameters.H5_TOKEN);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回重新登录提示内容
|
||||
|
@@ -3,7 +3,6 @@ package com.accompany.business.interceptor;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.annotation.H5Authorization;
|
||||
import com.accompany.common.constant.ApplicationConstant;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.utils.EnvComponent;
|
||||
@@ -60,13 +59,6 @@ public class LoginInterceptor extends BasicInterceptor {
|
||||
if (method.getAnnotation(Authorization.class) == null) {
|
||||
return true;
|
||||
}
|
||||
// 如果同时有H5Authorization注解并且h5_token不为空使用H5Authorization校验
|
||||
if (method.getAnnotation(H5Authorization.class) != null && StringUtils.isNotBlank(getH5Token(request))) {
|
||||
// 如果请求头部信息同时有ticket和token,则会使用Authorization注解校验用户登录信息
|
||||
if (StringUtils.isBlank(getTicket(request))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
String uid = this.getUid(request);
|
||||
if (StringUtils.isEmpty(uid) || StringUtils.equalsIgnoreCase(uid, "null") || !StringUtils.isNumeric(uid)) {
|
||||
logger.warn("uid illegal, uri={}, uid={}", request.getRequestURI(), uid);
|
||||
@@ -121,8 +113,4 @@ public class LoginInterceptor extends BasicInterceptor {
|
||||
return ticketStr;
|
||||
}
|
||||
|
||||
private String getH5JwtToken(HttpServletRequest request) {
|
||||
return request.getParameter(ApplicationConstant.PublicParameters.H5_TOKEN);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,105 +0,0 @@
|
||||
package com.accompany.business.interceptor;
|
||||
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.annotation.H5Authorization;
|
||||
import com.accompany.common.constant.ApplicationConstant;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.utils.StringUtils;
|
||||
import com.accompany.core.service.common.JedisService;
|
||||
import com.accompany.core.util.JwtUtils;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.SignatureException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Created by yuanyi on 2019/3/26.
|
||||
*/
|
||||
public class WebInterceptor extends BasicInterceptor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
|
||||
|
||||
@Autowired
|
||||
private JedisService jedisService;
|
||||
|
||||
@Autowired
|
||||
private JwtUtils jwtUtils;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
if (!(handler instanceof HandlerMethod)) {
|
||||
return true;
|
||||
}
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
Method method = handlerMethod.getMethod();
|
||||
// 不需要登录校验
|
||||
if (method.getAnnotation(H5Authorization.class) == null) {
|
||||
return true;
|
||||
}
|
||||
// 如果同时有Authorization注解并且ticket不为空使用Authorization校验
|
||||
if (method.getAnnotation(Authorization.class) != null && StringUtils.isNotBlank(getTicket(request))) {
|
||||
return true;
|
||||
}
|
||||
String uid = this.getUid(request);
|
||||
if (StringUtils.isEmpty(uid) || StringUtils.equalsIgnoreCase(uid, "null") || !StringUtils.isNumeric(uid)) {
|
||||
logger.warn("uid illegal, uri={}, uid={}", request.getRequestURI(), uid);
|
||||
writeLoginExpireResponse(response, 401, "Login status has expired, please log in again ~");
|
||||
return false;
|
||||
}
|
||||
// h5登录校验
|
||||
if (method.getAnnotation(H5Authorization.class) != null) {
|
||||
String token = getH5Token(request);
|
||||
if (StringUtils.isEmpty(token) || StringUtils.equalsIgnoreCase(token, "null")) {
|
||||
logger.warn("jwtToken is null, uri={}, uid={}", request.getRequestURI(), uid);
|
||||
writeLoginExpireResponse(response, 401, "Login status has expired, please log in again ~");
|
||||
return false;
|
||||
}
|
||||
String realToken = this.jedisService.hget(RedisKey.h5loginjwtoken.getKey(), uid);
|
||||
if (StringUtils.isEmpty(realToken)) {
|
||||
logger.warn("jwtToken is not exists, uri={}, uid={}, token={}", request.getRequestURI(), uid, token);
|
||||
writeLoginExpireResponse(response, 401, "Login status has expired, please log in again ~");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
jwtUtils.parseJWT(token);
|
||||
} catch (ExpiredJwtException e) {
|
||||
logger.error("jwtToken is expired,uid={},token={}", uid, token);
|
||||
writeLoginExpireResponse(response, 406, "need login!");
|
||||
return false;
|
||||
} catch (SignatureException e) {
|
||||
logger.error("signature is illegal,uid={},token={}", uid, token);
|
||||
writeLoginExpireResponse(response, 407, "Login status has expired, please log in again ~");
|
||||
return false;
|
||||
}
|
||||
if (!realToken.equals(token)) {
|
||||
logger.warn("jwtToken illegal, uri={}, uid={}, token={}", request.getRequestURI(), uid, token);
|
||||
writeLoginExpireResponse(response, 401, "Login status has expired, please log in again ~");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 uid, 以业务参数为首选
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private String getUid(HttpServletRequest request) {
|
||||
String uidStr = request.getParameter(ApplicationConstant.PublicParameters.UID);
|
||||
if (StringUtils.isEmpty(uidStr)) {
|
||||
uidStr = request.getHeader(ApplicationConstant.PublicParameters.PUB_UID);
|
||||
}
|
||||
return uidStr;
|
||||
}
|
||||
|
||||
}
|
@@ -45,7 +45,6 @@
|
||||
<hibernate-validator.version>6.0.17.Final</hibernate-validator.version>
|
||||
<hanlp.version>portable-1.6.8</hanlp.version>
|
||||
<hanlp-lucene-plugin.version>1.1.6</hanlp-lucene-plugin.version>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<java-jwt.version>3.10.3</java-jwt.version>
|
||||
<sitemesh.version>2.4.2</sitemesh.version>
|
||||
<pagehelper.version>6.1.0</pagehelper.version>
|
||||
@@ -78,6 +77,7 @@
|
||||
<pinyin4j.version>2.5.1</pinyin4j.version>
|
||||
<aws.version>2.30.37</aws.version>
|
||||
<dynamic-tp.version>1.2.2</dynamic-tp.version>
|
||||
<jjwt.version>0.12.5</jjwt.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
35
accompany-oauth/accompany-oauth-sdk/pom.xml
Normal file
35
accompany-oauth/accompany-oauth-sdk/pom.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-oauth</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>accompany-oauth-sdk</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>OAuth SDK模块 - 数据传输对象和接口定义</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-basic-sdk</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- JWT依赖 -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
<!-- 移除Spring Security OAuth2依赖,使用轻量化实现 -->
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@@ -0,0 +1,59 @@
|
||||
package com.accompany.oauth.constant;
|
||||
|
||||
/**
|
||||
* 认证类型枚举
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public enum GrantTypeEnum {
|
||||
/**
|
||||
* 密码登录
|
||||
*/
|
||||
PASSWORD("password", "密码登录"),
|
||||
|
||||
/**
|
||||
* 验证码登录
|
||||
*/
|
||||
VERIFY_CODE("verify_code", "验证码登录"),
|
||||
|
||||
/**
|
||||
* 邮箱登录
|
||||
*/
|
||||
EMAIL("email", "邮箱登录"),
|
||||
|
||||
/**
|
||||
* OpenID登录
|
||||
*/
|
||||
OPENID("openid", "OpenID登录"),
|
||||
|
||||
/**
|
||||
* Apple登录
|
||||
*/
|
||||
APPLE("apple", "Apple登录");
|
||||
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
GrantTypeEnum(String code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public static GrantTypeEnum fromCode(String code) {
|
||||
for (GrantTypeEnum type : values()) {
|
||||
if (type.code.equals(code)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("未知的认证类型: " + code);
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
package com.accompany.oauth.constant;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 登录类型
|
||||
*/
|
||||
public enum LoginTypeEnum {
|
||||
|
||||
/**
|
||||
* 微信
|
||||
*/
|
||||
WECHAT((byte) 1),
|
||||
/**
|
||||
* QQ
|
||||
*/
|
||||
QQ((byte) 2),
|
||||
/**
|
||||
* ID,萌声号或手机号
|
||||
*/
|
||||
ID((byte) 3),
|
||||
/**
|
||||
* 手机号一键登录
|
||||
*/
|
||||
PHONE((byte) 4),
|
||||
/**
|
||||
* 苹果账户
|
||||
*/
|
||||
APPLE((byte) 5),
|
||||
/**
|
||||
* 冷启动,ticket登录
|
||||
*/
|
||||
TICKET((byte) 6),
|
||||
|
||||
/**
|
||||
* 账号密码登录
|
||||
*/
|
||||
PASSWORD((byte) 7),
|
||||
|
||||
/**
|
||||
* 谷歌登录
|
||||
*/
|
||||
GOOGLE((byte) 8),
|
||||
|
||||
/**
|
||||
* line登录
|
||||
*/
|
||||
LINE((byte) 9),
|
||||
|
||||
/**
|
||||
* facebook登录
|
||||
*/
|
||||
FACEBOOK((byte) 10),
|
||||
|
||||
/**
|
||||
* 邮箱登录
|
||||
* */
|
||||
EMAIL((byte) 11),
|
||||
|
||||
;
|
||||
|
||||
private final byte value;
|
||||
|
||||
LoginTypeEnum(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static LoginTypeEnum get(int value) {
|
||||
Optional<LoginTypeEnum> result = Arrays.stream(LoginTypeEnum.values()).filter(loginTypeEnum ->
|
||||
loginTypeEnum.value == value).findAny();
|
||||
if (result.isPresent()) {
|
||||
return result.get();
|
||||
}
|
||||
throw new IllegalArgumentException("value not match");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package com.accompany.oauth.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 认证结果DTO
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Data
|
||||
public class AuthResult {
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
private String refreshToken;
|
||||
|
||||
/**
|
||||
* 过期时间(秒)
|
||||
*/
|
||||
private Long expiresIn;
|
||||
|
||||
/**
|
||||
* 令牌类型
|
||||
*/
|
||||
private String tokenType = "Bearer";
|
||||
|
||||
/**
|
||||
* 权限范围
|
||||
*/
|
||||
private String scope;
|
||||
|
||||
/**
|
||||
* 用户ID (兼容oauth2)
|
||||
*/
|
||||
private Long uid;
|
||||
|
||||
/**
|
||||
* 网易云信Token (兼容oauth2)
|
||||
*/
|
||||
private String netEaseToken = "";
|
||||
|
||||
/**
|
||||
* JWT ID (兼容oauth2)
|
||||
*/
|
||||
private String jti = "";
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.accompany.oauth.dto;
|
||||
|
||||
public class DayIpMaxRegisterLimitConfig {
|
||||
private boolean open;
|
||||
private long max;
|
||||
|
||||
public boolean getOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
public void setOpen(boolean open) {
|
||||
this.open = open;
|
||||
}
|
||||
|
||||
public long getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(long max) {
|
||||
this.max = max;
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package com.accompany.oauth.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RepeatedDeviceIpRegisterLimitConfig {
|
||||
private boolean open;
|
||||
private int repeatedDeviceNumLimit;
|
||||
private int repeatedIpNumLimit;
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package com.accompany.oauth.dto;
|
||||
|
||||
import com.accompany.oauth.ticket.Ticket;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 票据签发响应VO
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Data
|
||||
public class TicketResponseVO {
|
||||
|
||||
/**
|
||||
* 票据列表
|
||||
*/
|
||||
private List<TicketVO> tickets;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long uid;
|
||||
|
||||
/**
|
||||
* 签发类型
|
||||
*/
|
||||
private String issue_type = Ticket.MULTI_TYPE;
|
||||
|
||||
/**
|
||||
* 票据信息VO
|
||||
*/
|
||||
@Data
|
||||
public static class TicketVO {
|
||||
/**
|
||||
* 票据值
|
||||
*/
|
||||
private String ticket;
|
||||
|
||||
/**
|
||||
* 过期时间(秒)
|
||||
*/
|
||||
private Integer expiresIn;
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
package com.accompany.oauth.exception;
|
||||
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* OAuth认证异常基类
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class OAuthException extends RuntimeException {
|
||||
|
||||
private BusiStatus busiStatus;
|
||||
private Map<String, String> additionalInformation;
|
||||
|
||||
public OAuthException(BusiStatus busiStatus) {
|
||||
super(busiStatus.getMessage());
|
||||
this.busiStatus = busiStatus;
|
||||
}
|
||||
|
||||
public OAuthException(BusiStatus busiStatus, String message) {
|
||||
super(message);
|
||||
this.busiStatus = busiStatus;
|
||||
}
|
||||
|
||||
public OAuthException(BusiStatus busiStatus, Map<String, String> additionalInformation) {
|
||||
super(busiStatus.getMessage());
|
||||
this.busiStatus = busiStatus;
|
||||
this.additionalInformation = additionalInformation;
|
||||
}
|
||||
|
||||
public BusiStatus getBusiStatus() {
|
||||
return busiStatus;
|
||||
}
|
||||
|
||||
public void setBusiStatus(BusiStatus busiStatus) {
|
||||
this.busiStatus = busiStatus;
|
||||
}
|
||||
|
||||
public Map<String, String> getAdditionalInformation() {
|
||||
return additionalInformation;
|
||||
}
|
||||
|
||||
public void setAdditionalInformation(Map<String, String> additionalInformation) {
|
||||
this.additionalInformation = additionalInformation;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package com.accompany.oauth.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Token对模型
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Data
|
||||
public class TokenPair {
|
||||
|
||||
/**
|
||||
* 访问令牌
|
||||
*/
|
||||
private String accessToken;
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*/
|
||||
private String refreshToken;
|
||||
|
||||
/**
|
||||
* 过期时间(秒)
|
||||
*/
|
||||
private Long expiresIn;
|
||||
|
||||
/**
|
||||
* 令牌类型
|
||||
*/
|
||||
private String tokenType = "Bearer";
|
||||
|
||||
/**
|
||||
* 权限范围
|
||||
*/
|
||||
private String scope;
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.accompany.oauth.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Token验证结果模型
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Data
|
||||
public class TokenValidation {
|
||||
|
||||
/**
|
||||
* 是否有效
|
||||
*/
|
||||
private boolean valid;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 权限范围
|
||||
*/
|
||||
private Set<String> scopes;
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*/
|
||||
private Date expirationTime;
|
||||
|
||||
/**
|
||||
* 客户端ID
|
||||
*/
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
|
||||
public TokenValidation(boolean valid) {
|
||||
this.valid = valid;
|
||||
}
|
||||
|
||||
public static TokenValidation valid(Long userId, Date expirationTime, String clientId) {
|
||||
TokenValidation validation = new TokenValidation(true);
|
||||
validation.setUserId(userId);
|
||||
validation.setExpirationTime(expirationTime);
|
||||
validation.setClientId(clientId);
|
||||
return validation;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
package com.accompany.oauth.ticket;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Ticket类 - OAuth访问票据
|
||||
* 合并了接口和默认实现的功能
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Ticket implements Serializable {
|
||||
public static final String ONCE_TYPE = "once";
|
||||
public static final String MULTI_TYPE = "multi";
|
||||
|
||||
private String value;
|
||||
private Date expiration;
|
||||
private String ticketType = ONCE_TYPE.toLowerCase();
|
||||
private String accessToken;
|
||||
private Set<String> scope;
|
||||
private Map<String, Object> additionalInformation = Collections.emptyMap();
|
||||
|
||||
/**
|
||||
* 创建票据
|
||||
*/
|
||||
public Ticket(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制构造函数
|
||||
*/
|
||||
public Ticket(Ticket ticket) {
|
||||
this(ticket.getValue());
|
||||
setAdditionalInformation(ticket.getAdditionalInformation());
|
||||
setAccessToken(ticket.getAccessToken());
|
||||
setExpiration(ticket.getExpiration());
|
||||
setScope(ticket.getScope());
|
||||
setTicketType(ticket.getTicketType());
|
||||
}
|
||||
|
||||
public void setAdditionalInformation(Map<String, Object> additionalInformation) {
|
||||
this.additionalInformation = new LinkedHashMap<>(additionalInformation);
|
||||
}
|
||||
|
||||
public Map<String, Object> getAdditionalInformation() {
|
||||
return additionalInformation;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setTicketType(String ticketType) {
|
||||
this.ticketType = ticketType;
|
||||
}
|
||||
|
||||
public String getTicketType() {
|
||||
return ticketType;
|
||||
}
|
||||
|
||||
public void setExpiration(Date expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiresIn(int delta) {
|
||||
setExpiration(new Date(System.currentTimeMillis() + delta * 1000L));
|
||||
}
|
||||
|
||||
public int getExpiresIn() {
|
||||
return expiration != null ? Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L)
|
||||
.intValue() : 0;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setScope(Set<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public Set<String> getScope() {
|
||||
return scope;
|
||||
}
|
||||
}
|
85
accompany-oauth/accompany-oauth-service/pom.xml
Normal file
85
accompany-oauth/accompany-oauth-service/pom.xml
Normal file
@@ -0,0 +1,85 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-oauth</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>accompany-oauth-service</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>OAuth Service模块 - 业务逻辑实现</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-oauth-sdk</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-basic-service</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-sms-service</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-email-service</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- Redis支持 - 使用Redisson -->
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- 手机号验证支持 -->
|
||||
<dependency>
|
||||
<groupId>com.googlecode.libphonenumber</groupId>
|
||||
<artifactId>libphonenumber</artifactId>
|
||||
</dependency>
|
||||
<!-- Spring Boot Web支持 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- 移除Spring Security相关依赖,使用轻量化实现 -->
|
||||
|
||||
<!-- JWT 支持:API -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT 支持:实现 -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT 支持:JSON 序列化/反序列化(选一个)-->
|
||||
<!-- 如果你项目用 Jackson(Spring Boot 默认),选这个 -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@@ -0,0 +1,20 @@
|
||||
package com.accompany.oauth.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Data
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties("oauth2.server")
|
||||
public class OAuthConfig {
|
||||
|
||||
private String clientId;
|
||||
|
||||
private String clientSecret;
|
||||
|
||||
private String jwtSignKey;
|
||||
|
||||
}
|
@@ -0,0 +1,208 @@
|
||||
package com.accompany.oauth.service;
|
||||
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.enumeration.PartitionEnum;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Account;
|
||||
import com.accompany.core.model.AccountLoginRecord;
|
||||
import com.accompany.core.model.Users;
|
||||
import com.accompany.core.service.SysConfService;
|
||||
import com.accompany.core.service.account.AccountBlockCheckService;
|
||||
import com.accompany.core.service.account.AccountService;
|
||||
import com.accompany.core.service.account.LoginRecordService;
|
||||
import com.accompany.core.service.account.UserAppService;
|
||||
import com.accompany.core.service.common.JedisService;
|
||||
import com.accompany.core.service.region.RegionNetworkService;
|
||||
import com.accompany.core.service.user.UsersBaseService;
|
||||
import com.accompany.core.util.I18NMessageSourceUtil;
|
||||
import com.accompany.email.service.EmailService;
|
||||
import com.accompany.oauth.constant.LoginTypeEnum;
|
||||
import com.accompany.oauth.exception.OAuthException;
|
||||
import com.accompany.sms.service.SmsService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.accompany.core.enumeration.I18nAlertEnum.ACCOUNT_LOGIN_BLOCK_MSG;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AccountLoginService {
|
||||
|
||||
@Autowired
|
||||
private JedisService jedisService;
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
@Autowired
|
||||
private AccountManageService accountManageService;
|
||||
@Autowired
|
||||
private AccountBlockCheckService accountBlockCheckService;
|
||||
@Autowired
|
||||
private UserAppService userAppService;
|
||||
@Autowired
|
||||
private LoginRecordService loginRecordService;
|
||||
@Autowired
|
||||
private UsersBaseService usersBaseService;
|
||||
@Autowired
|
||||
private SmsService smsService;
|
||||
@Autowired
|
||||
private EmailService emailService;
|
||||
@Autowired
|
||||
private SysConfService sysConfService;
|
||||
@Autowired
|
||||
private RegionNetworkService regionService;
|
||||
|
||||
/**
|
||||
* 不允许登录的用户账号类型
|
||||
*/
|
||||
private final static List<Byte> NEED_INTERCEPT_USER_TYPE = Arrays.asList(Constant.DefUser.OFFICIAL,
|
||||
Constant.DefUser.ROBOT, Constant.DefUser.GAME_MANAGE_ROBOT);
|
||||
|
||||
public void login(Account account, LoginTypeEnum loginType, DeviceInfo deviceInfo, String openId) {
|
||||
|
||||
Long uid = account.getUid();
|
||||
|
||||
String deviceId = deviceInfo.getDeviceId();
|
||||
String ip = deviceInfo.getClientIp();
|
||||
String app = deviceInfo.getApp();
|
||||
String appVersion = deviceInfo.getAppVersion();
|
||||
|
||||
Date date = new Date();
|
||||
|
||||
// 拦截指定账号登录
|
||||
Users users = usersBaseService.getUsersByUid(account.getUid());
|
||||
if (users != null && NEED_INTERCEPT_USER_TYPE.contains(users.getDefUser())) {
|
||||
throw new ServiceException(BusiStatus.ILLEGAL_OPERATE);
|
||||
}
|
||||
|
||||
Long blockEndTime = accountBlockCheckService.checkReturnEndTime(account.getErbanNo(), account.getPhone(), account.getEmail(), deviceId, ip);
|
||||
//检查账号、设备号、号段是否封禁
|
||||
if (null != blockEndTime){
|
||||
Integer partitionId = null != users? users.getPartitionId(): PartitionEnum.ENGLISH.getId();
|
||||
Map<String, String> tipMap = Map.of("reason", I18NMessageSourceUtil.getMessage(ACCOUNT_LOGIN_BLOCK_MSG, new Object[]{users.getErbanNo()}, partitionId), "date", String.valueOf(blockEndTime));
|
||||
throw new OAuthException(BusiStatus.ACCOUNT_ERROR, tipMap);
|
||||
}
|
||||
|
||||
accountManageService.checkAccountCancel(uid);
|
||||
|
||||
//更新account信息
|
||||
String newToken = accountService.refreshAndGetNetEaseToken(account);
|
||||
|
||||
account.setNeteaseToken(newToken);
|
||||
account.setApp(deviceInfo.getApp());
|
||||
account.setAppVersion(deviceInfo.getAppVersion());
|
||||
account.setChannel(deviceInfo.getChannel());
|
||||
account.setLinkedmeChannel(deviceInfo.getLinkedmeChannel());
|
||||
account.setDeviceId(deviceInfo.getDeviceId());
|
||||
account.setImei(deviceInfo.getImei());
|
||||
account.setIspType(deviceInfo.getIspType());
|
||||
account.setModel(deviceInfo.getModel());
|
||||
account.setNetType(deviceInfo.getNetType());
|
||||
account.setOs(deviceInfo.getOs());
|
||||
account.setOsversion(deviceInfo.getOsVersion());
|
||||
account.setUpdateTime(date);
|
||||
account.setLastLoginTime(date);
|
||||
account.setLastLoginIp(ip);
|
||||
accountService.updateById(account);
|
||||
|
||||
//更新用户正在使用的app字段
|
||||
userAppService.updateCurrentApp(uid, app, date, ip, appVersion);
|
||||
|
||||
//将用户信息登记
|
||||
AccountLoginRecord accountLoginRecord = buildAccountLoginRecord(ip, account, loginType.getValue(), deviceInfo, openId);
|
||||
loginRecordService.addAccountLoginRecordAsync(accountLoginRecord);
|
||||
}
|
||||
|
||||
public AccountLoginRecord buildAccountLoginRecord(String ipAddress, Account account, byte loginType, DeviceInfo deviceInfo, String openId) {
|
||||
AccountLoginRecord accountLoginRecord = new AccountLoginRecord();
|
||||
accountLoginRecord.setLoginIp(ipAddress);
|
||||
accountLoginRecord.setLoginIpRegion(regionService.getRegion(ipAddress));
|
||||
accountLoginRecord.setUid(account.getUid());
|
||||
accountLoginRecord.setErbanNo(account.getErbanNo());
|
||||
accountLoginRecord.setLoginType(loginType);
|
||||
accountLoginRecord.setDeviceId(deviceInfo.getDeviceId());
|
||||
accountLoginRecord.setPhone(account.getPhone());
|
||||
accountLoginRecord.setEmail(account.getEmail());
|
||||
accountLoginRecord.setApp(account.getApp());
|
||||
accountLoginRecord.setAppVersion(deviceInfo.getAppVersion());
|
||||
accountLoginRecord.setIspType(deviceInfo.getIspType());
|
||||
accountLoginRecord.setModel(deviceInfo.getModel());
|
||||
accountLoginRecord.setOs(deviceInfo.getOs());
|
||||
accountLoginRecord.setOsversion(deviceInfo.getOsVersion());
|
||||
accountLoginRecord.setCreateTime(new Date());
|
||||
|
||||
if (loginType == LoginTypeEnum.APPLE.getValue()) {
|
||||
accountLoginRecord.setAppleUid(openId);
|
||||
}
|
||||
return accountLoginRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通用户需要用手机验证码登录,官方账号和公会账号不校验验证码
|
||||
*
|
||||
* @param account
|
||||
* @param code
|
||||
*/
|
||||
public void checkCodeByUserType(Account account, String code, LoginTypeEnum loginType) {
|
||||
//是否手机号登录
|
||||
boolean needVerifyCode = LoginTypeEnum.PHONE.getValue() == loginType.getValue()
|
||||
|| LoginTypeEnum.EMAIL.getValue() == loginType.getValue();
|
||||
if (!needVerifyCode) {
|
||||
return;
|
||||
}
|
||||
if (!StringUtils.hasText(code)) {
|
||||
throw new OAuthException(BusiStatus.VERIFY_CODE_ERROR);
|
||||
}
|
||||
|
||||
boolean verifyResult = LoginTypeEnum.PHONE.getValue() == loginType.getValue()?
|
||||
smsService.verifySmsCode(account.getPhone(), code):
|
||||
emailService.verifyEmailCode(account.getEmail(), code);
|
||||
if (!verifyResult) {
|
||||
throw new OAuthException(BusiStatus.VERIFY_CODE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理密码登录
|
||||
*
|
||||
* @param username 用户登录账号
|
||||
* @param accountPassword
|
||||
* @return 错误提示
|
||||
*/
|
||||
public void validPwd(String username, String password, String accountPassword) {
|
||||
String value = sysConfService.getDefaultSysConfValueById(Constant.SysConfId.PWD_LOGIN_DAY_WRONG_COUNT, "5");
|
||||
Long maxCount = Long.valueOf(value);
|
||||
|
||||
String cacheKey = RedisKey.user_login_pwd_wrong_day_count.getKey();
|
||||
Boolean exits = jedisService.exits(cacheKey);
|
||||
String countValue = jedisService.hget(cacheKey, username);
|
||||
Long currCount = StringUtils.isEmpty(countValue) ? 0L : Long.parseLong(countValue);
|
||||
if (currCount >= maxCount) {
|
||||
throw new OAuthException(BusiStatus.PWD_WRONG_OVER_LIMIT);
|
||||
}
|
||||
|
||||
if (!password.equals(accountPassword)) {
|
||||
currCount = jedisService.hincrBy(cacheKey, username, 1L);
|
||||
if (!exits) {
|
||||
jedisService.expire(cacheKey, 10 * 60);//10分钟后解锁
|
||||
}
|
||||
|
||||
if (currCount >= maxCount) {
|
||||
throw new OAuthException(BusiStatus.PWD_WRONG_OVER_LIMIT);
|
||||
} else {
|
||||
Long remainCount = maxCount - currCount;
|
||||
throw new OAuthException(BusiStatus.PASSWORD_ERROR_COUNT, String.format(BusiStatus.PASSWORD_ERROR_COUNT.getMessage(), remainCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,509 @@
|
||||
package com.accompany.oauth.service;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.common.netease.neteaseacc.result.TokenRet;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.BlankUtil;
|
||||
import com.accompany.common.utils.CommonUtil;
|
||||
import com.accompany.common.utils.DateTimeUtil;
|
||||
import com.accompany.common.utils.UUIDUtil;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Account;
|
||||
import com.accompany.core.model.GoogleOpenidRef;
|
||||
import com.accompany.core.model.UserCancelRecord;
|
||||
import com.accompany.core.model.Users;
|
||||
import com.accompany.core.mybatismapper.AccountMapper;
|
||||
import com.accompany.core.service.SysConfService;
|
||||
import com.accompany.core.service.account.AccountService;
|
||||
import com.accompany.core.service.account.ErBanNoService;
|
||||
import com.accompany.core.service.account.NetEaseService;
|
||||
import com.accompany.core.service.common.JedisService;
|
||||
import com.accompany.core.service.user.GoogleOpenidRefService;
|
||||
import com.accompany.core.service.user.UserCancelRecordService;
|
||||
import com.accompany.core.service.user.UsersBaseService;
|
||||
import com.accompany.core.util.MD5;
|
||||
import com.accompany.email.service.EmailService;
|
||||
import com.accompany.oauth.constant.LoginTypeEnum;
|
||||
import com.accompany.oauth.dto.DayIpMaxRegisterLimitConfig;
|
||||
import com.accompany.oauth.dto.RepeatedDeviceIpRegisterLimitConfig;
|
||||
import com.accompany.oauth.exception.OAuthException;
|
||||
import com.accompany.sms.service.SmsService;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author liuguofu
|
||||
* on 2015/3/20.
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AccountManageService {
|
||||
|
||||
@Autowired
|
||||
private JedisService jedisService;
|
||||
@Autowired
|
||||
private AccountMapper accountMapper;
|
||||
@Autowired
|
||||
private NetEaseService netEaseService;
|
||||
@Autowired
|
||||
private ErBanNoService erBanNoService;
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
@Autowired
|
||||
private UsersBaseService usersBaseService;
|
||||
@Autowired
|
||||
private UserCancelRecordService userCancelRecordService;
|
||||
@Autowired
|
||||
private SysConfService sysConfService;
|
||||
@Autowired
|
||||
private SmsService smsService;
|
||||
@Autowired
|
||||
private EmailService emailService;
|
||||
@Autowired
|
||||
private GoogleOpenidRefService googleOpenidRefService;
|
||||
|
||||
public Account getAccountPyUid(Long uid) {
|
||||
return accountService.getAccountByUid(uid);
|
||||
}
|
||||
|
||||
public Account getAccountPyUsername(String username, String password) {
|
||||
log.info("getAccountByUserName username:{} password:{}", username, password);
|
||||
Long erbanNo = Long.parseLong(username);
|
||||
return accountService.getAccountByErBanNo(erbanNo);
|
||||
}
|
||||
|
||||
public Account getOrGenAccountByPhone(String phone, String phoneAreaCode, String smsCode, DeviceInfo deviceInfo) {
|
||||
log.info("getOrGenAccountByPhone phone:{},smsCode:{},phoneAreaCode:{}", phone, smsCode, phoneAreaCode);
|
||||
final String lockVal = jedisService.lock(RedisKey.lock_register_by_phone.getKey(phone));
|
||||
try {
|
||||
if (BlankUtil.isBlank(lockVal)) {
|
||||
throw new ServiceException(BusiStatus.REQUEST_FAST);
|
||||
}
|
||||
Account account = accountService.getAccountByPhone(phone);
|
||||
if (account == null) {
|
||||
account = saveSignUpByPhone(phone, phoneAreaCode, deviceInfo);
|
||||
}
|
||||
return account;
|
||||
} finally {
|
||||
jedisService.unlock(RedisKey.lock_register_by_phone.getKey(phone), lockVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Account getOrGenAccountByEmail(String email, String code, DeviceInfo deviceInfo, String ipAddress) {
|
||||
log.info("getOrGenAccountByPhone email:{},code:{}", email, code);
|
||||
String lockVal = jedisService.lock(RedisKey.lock_register_by_email.getKey(email));
|
||||
try {
|
||||
if (BlankUtil.isBlank(lockVal)) {
|
||||
throw new ServiceException(BusiStatus.REQUEST_FAST);
|
||||
}
|
||||
Account account = accountService.getAccountByEmail(email);
|
||||
if (account == null) {
|
||||
account = saveSignUpByEmail(email, null, deviceInfo, ipAddress);
|
||||
}
|
||||
return account;
|
||||
} finally {
|
||||
jedisService.unlock(RedisKey.lock_register_by_email.getKey(email), lockVal);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public Account getOrGenAccountByOpenid(Byte type, String openid, String unionId, String idToken, DeviceInfo deviceInfo) {
|
||||
log.info("getOrGenAccountByOpenid openId:{},type:{},unionId:{}", openid, type, unionId);
|
||||
final String locKey = RedisKey.lock_register_by_openid.getKey(openid, unionId, String.valueOf(type));
|
||||
final String lockVal = jedisService.lock(locKey, 10 * 1000);
|
||||
try {
|
||||
if (BlankUtil.isBlank(lockVal)) {
|
||||
throw new ServiceException(BusiStatus.REQUEST_FAST);
|
||||
}
|
||||
|
||||
Account account = null;
|
||||
String thirdAccountEmail = null;
|
||||
|
||||
// openid是邮箱,则是新版本
|
||||
if (LoginTypeEnum.GOOGLE.getValue() == type && emailService.isValidEmail(openid)) {
|
||||
GoogleOpenidRef ref = googleOpenidRefService.getRefByEmail(openid, idToken);
|
||||
if (null != ref) {
|
||||
openid = ref.getOpenId();
|
||||
unionId = ref.getOpenId();
|
||||
thirdAccountEmail = ref.getEmail();
|
||||
|
||||
if (ref.isRegister()){
|
||||
Account emailAccount = accountService.getAccountByEmail(thirdAccountEmail);
|
||||
if (null != emailAccount && null == emailAccount.getThirdLoginType()){
|
||||
emailAccount.setThirdLoginType(type);
|
||||
emailAccount.setUnionId(unionId);
|
||||
emailAccount.setOpenId(openid);
|
||||
accountMapper.updateById(emailAccount);
|
||||
|
||||
account = emailAccount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null == account){
|
||||
account = accountService.getAccountByThird(type, unionId);
|
||||
}
|
||||
|
||||
if (null != account){
|
||||
|
||||
if (BlankUtil.isBlank(account.getUnionId()) || !account.getUnionId().equals(unionId)) {
|
||||
account.setUnionId(unionId);
|
||||
}
|
||||
account.setLastLoginTime(new Date());
|
||||
account.setLastLoginIp(deviceInfo.getClientIp());
|
||||
account.setUpdateTime(new Date());
|
||||
accountMapper.updateById(account);
|
||||
return account;
|
||||
}
|
||||
|
||||
checkRegisterLimit(deviceInfo.getDeviceId(), deviceInfo.getClientIp());
|
||||
|
||||
Date date = new Date();
|
||||
account = new Account();
|
||||
account.setLastLoginTime(date);
|
||||
account.setLastLoginIp(deviceInfo.getClientIp());
|
||||
account.setUpdateTime(date);
|
||||
account.setRegisterIp(deviceInfo.getClientIp());
|
||||
account.setSignTime(date);
|
||||
account.setState(Constant.AccountState.normal);
|
||||
account.setErbanNo(erBanNoService.getErBanNo());
|
||||
account.setPhone(CommonUtil.genSpecialPhoneForInitAccount(account.getErbanNo().toString()));
|
||||
// 三方登录信息
|
||||
account.setThirdLoginType(type);
|
||||
account.setUnionId(unionId);
|
||||
account.setOpenId(openid);
|
||||
account.setEmail(thirdAccountEmail);
|
||||
|
||||
account.setNeteaseToken(UUIDUtil.get());
|
||||
|
||||
account = fillDeviceInfo(account, deviceInfo);
|
||||
|
||||
accountMapper.insert(account);
|
||||
//写缓存
|
||||
accountService.writeAche(account);
|
||||
|
||||
String uidStr = String.valueOf(account.getUid());
|
||||
TokenRet tokenRet = netEaseService.createNetEaseAcc(uidStr, account.getNeteaseToken(), "", "", null);
|
||||
if (tokenRet.getCode() != 200) {
|
||||
log.info("注册云信账号失败,openid=" + openid + "&uid=" + uidStr + ",异常原因code=" + tokenRet.getCode());
|
||||
log.error("注册云信账号失败,openid=" + openid + "&uid=" + uidStr + ",异常原因code=" + tokenRet.getCode());
|
||||
throw new ServiceException("第三方登录失败,openid=" + openid + ",异常原因code=" + tokenRet.getCode());
|
||||
}
|
||||
|
||||
return account;
|
||||
|
||||
} finally {
|
||||
jedisService.unlock(locKey, lockVal);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRegisterLimit(String deviceId, String ipAddress) {
|
||||
if (!StringUtils.hasText(deviceId)) {
|
||||
throw new OAuthException(BusiStatus.DEVICE_ERROR);
|
||||
}
|
||||
|
||||
RepeatedDeviceIpRegisterLimitConfig repeatedConfig = getRepeatedDeviceIpLimitConfig();
|
||||
if (repeatedConfig.isOpen()) {
|
||||
long repeatedDeviceNum = accountService.lambdaQuery().eq(Account::getDeviceId, deviceId).count();
|
||||
if (repeatedDeviceNum >= repeatedConfig.getRepeatedDeviceNumLimit()) {
|
||||
throw new OAuthException(BusiStatus.REGISTER_FREQUENT);
|
||||
}
|
||||
|
||||
long repeatedIpNum = accountService.lambdaQuery().eq(Account::getRegisterIp, ipAddress).count();
|
||||
if (repeatedIpNum >= repeatedConfig.getRepeatedIpNumLimit()) {
|
||||
throw new OAuthException(BusiStatus.REGISTER_FREQUENT);
|
||||
}
|
||||
}
|
||||
|
||||
//当日单个ip注册数
|
||||
DayIpMaxRegisterLimitConfig config = getIpMaxLimitConfig();
|
||||
if (config.getOpen()) {
|
||||
long count = accountService.getRegisterIpCountByOneDay(ipAddress);
|
||||
if (count >= config.getMax()) {
|
||||
throw new OAuthException(BusiStatus.REGISTER_FREQUENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过手机号码注册,独立账号系统,不掺杂业务
|
||||
*
|
||||
* @param phone
|
||||
* @return
|
||||
*/
|
||||
@SneakyThrows
|
||||
public Account saveSignUpByPhone(String phone, String phoneAreaCode, DeviceInfo deviceInfo) {
|
||||
checkRegisterLimit(deviceInfo.getDeviceId(), deviceInfo.getClientIp());
|
||||
|
||||
Date date = new Date();
|
||||
Account account = new Account();
|
||||
account.setPhone(phone);
|
||||
account.setPhoneAreaCode(phoneAreaCode);
|
||||
// if (!StringUtils.isEmpty(password)) {
|
||||
// account.setPassword(encryptPassword(password));
|
||||
// }
|
||||
account.setNeteaseToken(UUIDUtil.get());
|
||||
account.setLastLoginTime(date);
|
||||
account.setLastLoginIp(deviceInfo.getClientIp());
|
||||
account.setUpdateTime(date);
|
||||
account.setRegisterIp(deviceInfo.getClientIp());
|
||||
account.setSignTime(date);
|
||||
account.setState(Constant.AccountState.normal);
|
||||
account.setErbanNo(erBanNoService.getErBanNo());
|
||||
account = fillDeviceInfo(account, deviceInfo);
|
||||
account.setSignupApp(deviceInfo.getApp());
|
||||
|
||||
accountMapper.insert(account);
|
||||
accountService.writeAche(account);
|
||||
|
||||
String uidStr = String.valueOf(account.getUid());
|
||||
TokenRet tokenRet = netEaseService.createNetEaseAcc(uidStr, account.getNeteaseToken(), "", "", null);
|
||||
if (tokenRet.getCode() != 200) {
|
||||
log.error("手机号码phone=" + phone + "注册异常,异常原因code=" + tokenRet.getCode());
|
||||
log.info("手机号码phone=" + phone + "注册异常,异常原因code=" + tokenRet.getCode());
|
||||
throw new OAuthException(BusiStatus.REGISTER_NETEASE_FAIL);
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private Account saveSignUpByEmail(String email, String password, DeviceInfo deviceInfo, String ipAddress) {
|
||||
checkRegisterLimit(deviceInfo.getDeviceId(), ipAddress);
|
||||
|
||||
Date date = new Date();
|
||||
Account account = new Account();
|
||||
account.setEmail(email);
|
||||
if (StringUtils.hasText(password)) {
|
||||
account.setPassword(MD5.getMD5(password));
|
||||
}
|
||||
account.setNeteaseToken(UUIDUtil.get());
|
||||
account.setLastLoginTime(date);
|
||||
account.setLastLoginIp(ipAddress);
|
||||
account.setUpdateTime(date);
|
||||
account.setRegisterIp(ipAddress);
|
||||
account.setSignTime(date);
|
||||
account.setState(Constant.AccountState.normal);
|
||||
account.setErbanNo(erBanNoService.getErBanNo());
|
||||
account = fillDeviceInfo(account, deviceInfo);
|
||||
|
||||
accountMapper.insert(account);
|
||||
accountService.writeAche(account);
|
||||
String uidStr = String.valueOf(account.getUid());
|
||||
TokenRet tokenRet = netEaseService.createNetEaseAcc(uidStr, account.getNeteaseToken(), "", "", null);
|
||||
if (tokenRet.getCode() != 200) {
|
||||
log.error("邮件email {} 注册异常,异常原因code {}", email, tokenRet.getCode());
|
||||
throw new OAuthException(BusiStatus.REGISTER_NETEASE_FAIL);
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
private Account fillDeviceInfo(Account account, DeviceInfo deviceInfo) {
|
||||
if (deviceInfo != null) {
|
||||
account.setSignupApp(deviceInfo.getApp());
|
||||
account.setApp(deviceInfo.getApp());
|
||||
account.setAppVersion(deviceInfo.getAppVersion());
|
||||
account.setChannel(deviceInfo.getChannel());
|
||||
account.setLinkedmeChannel(deviceInfo.getLinkedmeChannel());
|
||||
account.setDeviceId(deviceInfo.getDeviceId());
|
||||
account.setImei(deviceInfo.getImei());
|
||||
account.setIspType(deviceInfo.getIspType());
|
||||
account.setModel(deviceInfo.getModel());
|
||||
account.setNetType(deviceInfo.getNetType());
|
||||
account.setOs(deviceInfo.getOs());
|
||||
account.setOsversion(deviceInfo.getOsVersion());
|
||||
account.setDeviceInfo(JSON.toJSONString(deviceInfo));
|
||||
}
|
||||
return account;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
* 两个场景调用 => 客户端未登录 忘记密码, 此时uid 为 null 登录状态下忘记密码 uid有值
|
||||
* @param uid
|
||||
* @param phone
|
||||
* @param password
|
||||
* @param resetCode
|
||||
* @return 1:成功 2:重置码无效 3:用户不存在
|
||||
*/
|
||||
public void resetPasswordByResetCode(Long uid, String phone, String password, String resetCode) {
|
||||
if (phone.contains("*")) {
|
||||
Account account = accountService.getById(uid);
|
||||
if (account == null) {
|
||||
throw new OAuthException(BusiStatus.USER_NOT_EXISTED);
|
||||
}
|
||||
phone = account.getPhone();
|
||||
if (!CommonUtil.checkPhoneFormat(account.getPhoneAreaCode(), account.getPhone())) {
|
||||
throw new OAuthException(BusiStatus.PHONE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
long count = accountService.countByPhone(phone);
|
||||
if (count > 1L) {
|
||||
throw new OAuthException(BusiStatus.PHONE_BIND_TOO_MANY_ACCOUNT);
|
||||
}
|
||||
|
||||
Account account = accountService.getAccountByPhone(phone);
|
||||
if (null == account || (uid != null && !account.getUid().equals(uid))) {
|
||||
throw new OAuthException(BusiStatus.PHONE_BIND_ERROR);
|
||||
}
|
||||
|
||||
//检验验证码
|
||||
if (!smsService.verifySmsCodeByCache(phone, resetCode)) {
|
||||
throw new OAuthException(BusiStatus.INVALID_IDENTIFYING_CODE);
|
||||
}
|
||||
|
||||
accountService.resetAccountPwd(account.getUid(), password);
|
||||
//成功后删除验证码缓存
|
||||
smsService.delSmsCodeCache(phone);
|
||||
|
||||
// 删除用户信息缓存
|
||||
jedisService.hdel(RedisKey.user.getKey(), account.getUid().toString());
|
||||
jedisService.hdel(RedisKey.user_summary.getKey(), account.getUid().toString());
|
||||
accountService.delNickPasswordCache(account.getErbanNo());
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
* 两个场景调用 => 客户端未登录 忘记密码, 此时uid 为 null 登录状态下忘记密码 uid有值
|
||||
* @param uid
|
||||
* @param email
|
||||
* @param password
|
||||
* @param code
|
||||
* @return 1:成功 2:重置码无效 3:用户不存在
|
||||
*/
|
||||
public void resetPasswordByEmailCode(Long uid, String email, String password, String code) {
|
||||
emailService.validEmailAddress(email);
|
||||
|
||||
long count = accountService.countByEmail(email);
|
||||
if (count > 1L) {
|
||||
throw new OAuthException(BusiStatus.EMAIL_BIND_TOO_MANY_ACCOUNT);
|
||||
}
|
||||
|
||||
Account account = accountService.getAccountByEmail(email);
|
||||
if (null == account) {
|
||||
throw new OAuthException(BusiStatus.ACCOUNT_NOT_BIND_EMAIL);
|
||||
} else if (null != uid && !account.getUid().equals(uid)) {
|
||||
throw new OAuthException(BusiStatus.ACCOUNT_BIND_EMAIL_DIFF);
|
||||
}
|
||||
|
||||
//检验验证码
|
||||
if (!emailService.verifyCodeByCache(email, code)) {
|
||||
throw new OAuthException(BusiStatus.INVALID_IDENTIFYING_EMAIL_CODE);
|
||||
}
|
||||
|
||||
accountService.resetAccountPwd(account.getUid(), password);
|
||||
//成功后删除验证码缓存
|
||||
emailService.delCodeCache(email);
|
||||
|
||||
// 删除用户信息缓存
|
||||
jedisService.hdel(RedisKey.user.getKey(), account.getUid().toString());
|
||||
jedisService.hdel(RedisKey.user_summary.getKey(), account.getUid().toString());
|
||||
accountService.delNickPasswordCache(account.getErbanNo());
|
||||
}
|
||||
|
||||
public void resetPasswordByOldPassword(String phone, String password, String newPassword) {
|
||||
Account account = accountService.getAccountByPhone(phone);
|
||||
if (null == account) {
|
||||
throw new ServiceException(BusiStatus.USER_NOT_EXISTED);
|
||||
}
|
||||
|
||||
String oldPwd = account.getPassword();
|
||||
password = MD5.getMD5(password);
|
||||
if (!StringUtils.hasText(password) || !password.equals(oldPwd)) {
|
||||
throw new ServiceException(BusiStatus.OLD_PASSWORD_ERROR);
|
||||
}
|
||||
|
||||
accountService.resetAccountPwd(account.getUid(), newPassword);
|
||||
accountService.delNickPasswordCache(account.getErbanNo());
|
||||
|
||||
//记录最近30天内绑定手机号
|
||||
jedisService.setex(RedisKey.modify_pwd_sign.getKey(String.valueOf(account.getUid())),
|
||||
30 * 24 * 60 * 60, String.valueOf(new Date().getTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置登录密码
|
||||
* @param uid
|
||||
* @param password
|
||||
* @return
|
||||
*/
|
||||
public void setupInitialPassword(Long uid, String password) {
|
||||
Account account = accountService.getById(uid);
|
||||
if (account == null) {
|
||||
throw new ServiceException(BusiStatus.INVALID_USER);
|
||||
}
|
||||
|
||||
Boolean result = accountService.updateAccountPwd(account.getUid(), password);
|
||||
if (!result) {
|
||||
throw new ServiceException(BusiStatus.INVALID_REQUEST);
|
||||
}
|
||||
|
||||
// 更新用户缓存
|
||||
this.jedisService.hdel(RedisKey.user.getKey(), account.getUid().toString());
|
||||
this.jedisService.hdel(RedisKey.user_summary.getKey(), account.getUid().toString());
|
||||
accountService.delNickPasswordCache(account.getErbanNo());
|
||||
}
|
||||
|
||||
public void checkAccountCancel(Long uid) {
|
||||
log.info("检查账号{}是否已注销", uid);
|
||||
Users users = usersBaseService.getUsersByUid(uid);
|
||||
if (ObjectUtil.isNull(users)) {
|
||||
log.info("获取不到用户{}users账号信息", uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Constant.UserUseStatus.cancel.equals(users.getUseStatus())) return;
|
||||
|
||||
UserCancelRecord userCancelRecord = userCancelRecordService.getById(uid);
|
||||
|
||||
if (ObjectUtil.isNull(userCancelRecord)) {
|
||||
//获取不到注销账号信息
|
||||
log.info("获取不到用户{}注销信息", uid);
|
||||
throw new OAuthException(BusiStatus.ACCOUNT_CANCEL_INFO_NOT_EXIST);
|
||||
}
|
||||
|
||||
|
||||
log.info("检测到注销账号{}昵称{}于{}尝试登录", users.getErbanNo(), userCancelRecord.getNick(), DateTimeUtil.convertDate(userCancelRecord.getUpdateTime()));
|
||||
|
||||
Integer surviveTime = Integer.valueOf(sysConfService.getDefaultSysConfValueById(Constant.SysConfId.USER_RECOVER_CREDENTIALS_SURVIVE_TIME, String.valueOf(3 * 60)));
|
||||
//写入凭证标识
|
||||
jedisService.setex(RedisKey.cancel_user_recover_credentials.getKey(String.valueOf(users.getErbanNo())), surviveTime, String.valueOf(uid));
|
||||
|
||||
Map<String, String> tipMap = Map.of("erbanNo", String.valueOf(users.getErbanNo()), "cancelDate", String.valueOf(userCancelRecord.getUpdateTime().getTime()),
|
||||
"nick", userCancelRecord.getNick(), "avatar", userCancelRecord.getAvatar());
|
||||
throw new OAuthException(BusiStatus.ACCOUNT_CANCEL, tipMap);
|
||||
}
|
||||
|
||||
private DayIpMaxRegisterLimitConfig getIpMaxLimitConfig() {
|
||||
String config = sysConfService.getSysConfValueById(Constant.SysConfId.IP_MAX_REGISTER_LIMIT_CONFIG);
|
||||
if (!StringUtils.hasText(config)) {
|
||||
throw new OAuthException(BusiStatus.ALREADY_NOTEXISTS_CONFIG);
|
||||
}
|
||||
return JSON.parseObject(config, DayIpMaxRegisterLimitConfig.class);
|
||||
}
|
||||
|
||||
private RepeatedDeviceIpRegisterLimitConfig getRepeatedDeviceIpLimitConfig() {
|
||||
String config = sysConfService.getSysConfValueById(Constant.SysConfId.REPEATED_DEVICE_IP_REGISTER_LIMIT_CONFIG);
|
||||
if (!StringUtils.hasText(config)) {
|
||||
throw new OAuthException(BusiStatus.ALREADY_NOTEXISTS_CONFIG);
|
||||
}
|
||||
return JSON.parseObject(config, RepeatedDeviceIpRegisterLimitConfig.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,125 @@
|
||||
package com.accompany.oauth.service;
|
||||
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.CommonUtil;
|
||||
import com.accompany.common.utils.DESUtils;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Account;
|
||||
import com.accompany.core.util.KeyStore;
|
||||
import com.accompany.core.util.MD5;
|
||||
import com.accompany.oauth.constant.LoginTypeEnum;
|
||||
import com.accompany.oauth.exception.OAuthException;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 用户服务 - 用户认证和信息查询
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Service
|
||||
public class AuthenticateService {
|
||||
|
||||
@Autowired
|
||||
private AccountManageService accountManageService;
|
||||
@Autowired
|
||||
private AccountLoginService accountLoginService;
|
||||
|
||||
/**
|
||||
* 通过密码认证用户
|
||||
*
|
||||
* @param username 手机号
|
||||
* @param password 密码
|
||||
* @return 用户详情
|
||||
* @throws OAuthException 认证失败
|
||||
*/
|
||||
@SneakyThrows
|
||||
public Account authenticateByPassword(String username, String password) {
|
||||
username = DESUtils.DESAndBase64Decrypt(username, KeyStore.DES_ENCRYPT_KEY);
|
||||
password = DESUtils.DESAndBase64Decrypt(password, KeyStore.DES_ENCRYPT_KEY);
|
||||
password = MD5.getMD5(password);
|
||||
|
||||
Account account = accountManageService.getAccountPyUsername(username, password);
|
||||
if (account == null) {
|
||||
throw new OAuthException(BusiStatus.USER_NOT_EXISTED);
|
||||
}
|
||||
|
||||
accountLoginService.validPwd(username, password, account.getPassword());
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
|
||||
public Account authenticateByVerifyCode(String phone, String phoneAreaCode, String code, DeviceInfo deviceInfo) {
|
||||
if (!CommonUtil.checkPhoneFormat(phoneAreaCode, phone)){
|
||||
throw new ServiceException(BusiStatus.PARAMERROR);
|
||||
}
|
||||
|
||||
Account account = accountManageService.getOrGenAccountByPhone(phone, phoneAreaCode, code, deviceInfo);
|
||||
//校验验证码
|
||||
accountLoginService.checkCodeByUserType(account, code, LoginTypeEnum.PHONE);
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过邮箱认证用户
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @param code 验证码
|
||||
* @param deviceInfo
|
||||
* @return 用户详情
|
||||
* @throws OAuthException 认证失败
|
||||
*/
|
||||
public Account authenticateByEmail(String email, String code, DeviceInfo deviceInfo) {
|
||||
Account account = accountManageService.getOrGenAccountByEmail(email, code, deviceInfo, deviceInfo.getClientIp());
|
||||
|
||||
//校验验证码
|
||||
accountLoginService.checkCodeByUserType(account, code, LoginTypeEnum.EMAIL);
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过OpenID认证用户
|
||||
*
|
||||
* @param openId OpenID
|
||||
* @param type 第三方类型 (1-微信, 2-Apple等)
|
||||
* @return 用户详情
|
||||
* @throws OAuthException 认证失败
|
||||
*/
|
||||
public Account authenticateByOpenId(Byte type, String openId, String unionId, String idToken, DeviceInfo deviceInfo) {
|
||||
return accountManageService.getOrGenAccountByOpenid(type, openId, unionId, idToken, deviceInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取用户详情
|
||||
*
|
||||
* @param uid 用户ID
|
||||
* @return 用户详情
|
||||
* @throws OAuthException 用户不存在
|
||||
*/
|
||||
public Account getUserByUid(Long uid) {
|
||||
return accountManageService.getAccountPyUid(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户状态是否可用
|
||||
*
|
||||
* @throws OAuthException 用户不可用
|
||||
*/
|
||||
public void checkUserStatus(Account account) {
|
||||
if (Constant.AccountState.block.equals(account.getState())) {
|
||||
throw new OAuthException(BusiStatus.ACCOUNT_BLOCK_ERROR);
|
||||
}
|
||||
|
||||
if (Constant.AccountState.cancel.equals(account.getState())) {
|
||||
throw new OAuthException(BusiStatus.ACCOUNT_CANCEL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
package com.accompany.oauth.service;
|
||||
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.model.Account;
|
||||
import com.accompany.oauth.constant.GrantTypeEnum;
|
||||
import com.accompany.oauth.constant.LoginTypeEnum;
|
||||
import com.accompany.oauth.dto.AuthResult;
|
||||
import com.accompany.oauth.exception.OAuthException;
|
||||
import com.accompany.oauth.token.TokenManager;
|
||||
import com.accompany.oauth.model.TokenPair;
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 认证服务 - 统一认证入口
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Service
|
||||
public class AuthenticationService {
|
||||
|
||||
@Autowired
|
||||
private AuthenticateService authenticateService;
|
||||
@Autowired
|
||||
private AccountLoginService accountLoginService;
|
||||
@Autowired
|
||||
private TokenManager tokenManager;
|
||||
|
||||
/**
|
||||
* 用户认证 - 简化接口(直接传参)
|
||||
*
|
||||
* @param grantType 授权类型/手机号/邮箱
|
||||
* @param password 密码
|
||||
* @param code 验证码
|
||||
* @param deviceInfo 设备信息
|
||||
* @return 认证结果
|
||||
* @throws OAuthException 认证失败
|
||||
*/
|
||||
public AuthResult authenticate(String grantType,
|
||||
String username, String password,
|
||||
String phone, String phoneAreaCode, String email,
|
||||
String code, DeviceInfo deviceInfo) {
|
||||
GrantTypeEnum grantTypeEnum = GrantTypeEnum.fromCode(grantType);
|
||||
|
||||
// 1. 根据授权类型进行用户认证
|
||||
LoginTypeEnum loginTypeEnum = null;
|
||||
Account account = null;
|
||||
|
||||
switch (grantTypeEnum) {
|
||||
case PASSWORD:
|
||||
loginTypeEnum = LoginTypeEnum.ID;
|
||||
account = authenticateService.authenticateByPassword(username, password);
|
||||
break;
|
||||
case VERIFY_CODE:
|
||||
loginTypeEnum = LoginTypeEnum.PHONE;
|
||||
account = authenticateService.authenticateByVerifyCode(phone, phoneAreaCode, code, deviceInfo);
|
||||
break;
|
||||
case EMAIL:
|
||||
loginTypeEnum = LoginTypeEnum.EMAIL;
|
||||
account = authenticateService.authenticateByEmail(email, code, deviceInfo);
|
||||
break;
|
||||
default:
|
||||
throw new OAuthException(BusiStatus.INVALID_GRANT);
|
||||
}
|
||||
|
||||
// 2. 检查用户状态
|
||||
authenticateService.checkUserStatus(account);
|
||||
|
||||
accountLoginService.login(account, loginTypeEnum, deviceInfo, null);
|
||||
|
||||
// 3. 生成Token
|
||||
TokenPair tokenPair = tokenManager.generateToken(account.getUid());
|
||||
|
||||
// 4. 构建认证结果
|
||||
return buildAuthResult(tokenPair, account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方认证
|
||||
*
|
||||
* @param type 第三方类型
|
||||
* @param openId OpenID
|
||||
* @param unionId UnionID
|
||||
* @param idToken ID Token
|
||||
* @param deviceInfo 设备信息
|
||||
* @return 认证结果
|
||||
* @throws OAuthException 认证失败
|
||||
*/
|
||||
public AuthResult authenticateByThirdParty(Byte type, String openId, String unionId, String idToken, DeviceInfo deviceInfo) {
|
||||
// 1. 第三方认证
|
||||
Account account = authenticateService.authenticateByOpenId(type, openId, unionId, idToken, deviceInfo);
|
||||
|
||||
// 2. 检查用户状态
|
||||
authenticateService.checkUserStatus(account);
|
||||
|
||||
// 4. 生成Token
|
||||
TokenPair tokenPair = tokenManager.generateToken(account.getUid());
|
||||
|
||||
// 5. 构建认证结果
|
||||
return buildAuthResult(tokenPair, account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销Token
|
||||
*
|
||||
* @param token 访问令牌
|
||||
*/
|
||||
public void revokeToken(String token) {
|
||||
tokenManager.revokeToken(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建认证结果
|
||||
*
|
||||
* @param tokenPair Token对
|
||||
* @return 认证结果
|
||||
*/
|
||||
private AuthResult buildAuthResult(TokenPair tokenPair, Account account) {
|
||||
// 构建认证结果
|
||||
AuthResult authResult = new AuthResult();
|
||||
authResult.setAccessToken(tokenPair.getAccessToken());
|
||||
authResult.setRefreshToken(tokenPair.getRefreshToken());
|
||||
authResult.setExpiresIn(tokenPair.getExpiresIn());
|
||||
authResult.setTokenType(tokenPair.getTokenType());
|
||||
authResult.setScope(tokenPair.getScope());
|
||||
|
||||
// 填充兼容字段
|
||||
authResult.setUid(account.getUid());
|
||||
authResult.setNetEaseToken(account.getNeteaseToken());
|
||||
|
||||
return authResult;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,144 @@
|
||||
package com.accompany.oauth.ticket;
|
||||
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.model.Account;
|
||||
import com.accompany.core.model.AccountLoginRecord;
|
||||
import com.accompany.core.service.account.AccountService;
|
||||
import com.accompany.core.service.account.LoginRecordService;
|
||||
import com.accompany.core.service.account.UserAppService;
|
||||
import com.accompany.oauth.constant.LoginTypeEnum;
|
||||
import com.accompany.oauth.dto.TicketResponseVO;
|
||||
import com.accompany.oauth.exception.OAuthException;
|
||||
import com.accompany.oauth.token.TokenManager;
|
||||
import com.accompany.oauth.model.TokenValidation;
|
||||
import com.accompany.oauth.service.AccountLoginService;
|
||||
import com.accompany.oauth.service.AuthenticateService;
|
||||
import com.accompany.oauth.util.JwtUtil;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.client.codec.StringCodec;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Ticket服务
|
||||
* 迁移自OAuth2模块的TicketServices,简化实现
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Service
|
||||
public class TicketService implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private TokenManager tokenManager;
|
||||
|
||||
@Autowired
|
||||
private AuthenticateService authenticateService;
|
||||
|
||||
@Autowired
|
||||
private JwtUtil jwtUtil;
|
||||
|
||||
@Autowired
|
||||
private UserAppService userAppService;
|
||||
@Autowired
|
||||
private AccountLoginService accountLoginService;
|
||||
@Autowired
|
||||
private LoginRecordService loginRecordService;
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
private RMapCache<Long, String> ticketCache;
|
||||
|
||||
/**
|
||||
* 签发票据
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @return 票据响应
|
||||
*/
|
||||
public TicketResponseVO issueTicket(String accessToken) {
|
||||
// 1. 验证访问令牌
|
||||
TokenValidation validation = tokenManager.validateToken(accessToken);
|
||||
if (!validation.isValid()) {
|
||||
throw new OAuthException(BusiStatus.INVALID_TOKEN);
|
||||
}
|
||||
|
||||
// 2. 获取用户信息
|
||||
Account account = authenticateService.getUserByUid(validation.getUserId());
|
||||
authenticateService.checkUserStatus(account);
|
||||
|
||||
Date expiration = validation.getExpirationTime();
|
||||
|
||||
// 4. 创建票据
|
||||
Ticket ticket = new Ticket(UUID.randomUUID().toString());
|
||||
ticket.setAccessToken(accessToken);
|
||||
ticket.setExpiration(expiration);
|
||||
ticket.setTicketType(Ticket.MULTI_TYPE);
|
||||
ticket.setScope(validation.getScopes());
|
||||
|
||||
// 5. 增强票据(JWT签名)
|
||||
String ticketValue = jwtUtil.generateTicket(ticket, account.getUid());
|
||||
ticket.setValue(ticketValue);
|
||||
|
||||
// 6. 存储票据
|
||||
ticketCache.fastPut(account.getUid(), ticketValue, ticket.getExpiresIn(), TimeUnit.SECONDS);
|
||||
|
||||
// 7. 构建响应
|
||||
TicketResponseVO response = new TicketResponseVO();
|
||||
response.setUid(account.getUid());
|
||||
|
||||
List<TicketResponseVO.TicketVO> tickets = new ArrayList<>();
|
||||
tickets.add(createTicketVo(ticket));
|
||||
response.setTickets(tickets);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建票据VO
|
||||
*
|
||||
* @param ticket 票据
|
||||
* @return 票据VO
|
||||
*/
|
||||
private TicketResponseVO.TicketVO createTicketVo(Ticket ticket) {
|
||||
TicketResponseVO.TicketVO ticketVo = new TicketResponseVO.TicketVO();
|
||||
ticketVo.setTicket(ticket.getValue());
|
||||
ticketVo.setExpiresIn(ticket.getExpiresIn());
|
||||
return ticketVo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存登录记录(异步)
|
||||
*
|
||||
* @param uid 用户ID
|
||||
* @param ipAddress IP地址
|
||||
* @param deviceInfo 设备信息
|
||||
*/
|
||||
public void saveLoginRecord(Long uid, String ipAddress, DeviceInfo deviceInfo) {
|
||||
Optional.ofNullable(uid).ifPresent(id -> {
|
||||
userAppService.updateCurrentApp(uid, deviceInfo.getApp(), new Date(), ipAddress, deviceInfo.getAppVersion());
|
||||
|
||||
long count = loginRecordService.countLoginRecordToday(id);
|
||||
if (count <= 0L) {
|
||||
Account account = accountService.getAccountByUid(id);
|
||||
Optional.ofNullable(account).ifPresent(acc -> {
|
||||
AccountLoginRecord record = accountLoginService.buildAccountLoginRecord(ipAddress, acc, LoginTypeEnum.TICKET.getValue(), deviceInfo, null);
|
||||
loginRecordService.addAccountLoginRecord(record);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
ticketCache = redissonClient.getMapCache(RedisKey.uid_ticket.getKey(), StringCodec.INSTANCE);
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
package com.accompany.oauth.token;
|
||||
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.util.StringUtils;
|
||||
import com.accompany.oauth.exception.OAuthException;
|
||||
import com.accompany.oauth.model.TokenPair;
|
||||
import com.accompany.oauth.model.TokenValidation;
|
||||
import com.accompany.oauth.util.JwtUtil;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.client.codec.StringCodec;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Token管理器 - 使用Redisson进行Token存储和管理
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Component
|
||||
public class TokenManager implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
public JwtUtil jwtUtil;
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
private RMapCache<Long, String> tokenCache;
|
||||
|
||||
private final String defaultScope = "read write";
|
||||
|
||||
public TokenPair generateToken(Long uid) {
|
||||
// 生成JWT token
|
||||
Date now = new Date();
|
||||
String accessToken = jwtUtil.generateAccessToken(uid, now);
|
||||
String refreshToken = jwtUtil.generateRefreshToken(uid, now);
|
||||
|
||||
// 存储access token
|
||||
tokenCache.fastPut(uid, accessToken, jwtUtil.getAccessTokenExpiration(), TimeUnit.SECONDS);
|
||||
|
||||
TokenPair tokenPair = new TokenPair();
|
||||
tokenPair.setAccessToken(accessToken);
|
||||
tokenPair.setRefreshToken(refreshToken);
|
||||
tokenPair.setExpiresIn(jwtUtil.getAccessTokenExpiration());
|
||||
tokenPair.setTokenType("Bearer");
|
||||
tokenPair.setScope(defaultScope);
|
||||
|
||||
return tokenPair;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证Token
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @return 验证结果
|
||||
*/
|
||||
public TokenValidation validateToken(String token) {
|
||||
// 首先验证JWT格式和签名
|
||||
Claims claims = jwtUtil.validateAndParseToken(token);
|
||||
// 提取token信息
|
||||
Long uid = Long.valueOf(claims.getSubject());
|
||||
|
||||
// 检查Redis中是否存在该token
|
||||
String cacheToken = tokenCache.get(uid);
|
||||
if (StringUtils.isBlank(cacheToken) || !cacheToken.equals(token)) {
|
||||
throw new OAuthException(BusiStatus.INVALID_TOKEN);
|
||||
}
|
||||
|
||||
String clientId = claims.get("client_id", String.class);
|
||||
Date expirationTime = claims.getExpiration();
|
||||
|
||||
return TokenValidation.valid(uid, expirationTime, clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤销Token
|
||||
*
|
||||
* @param token 访问令牌
|
||||
*/
|
||||
public void revokeToken(String token) {
|
||||
Claims claims = jwtUtil.validateAndParseToken(token);
|
||||
Long uid = Long.valueOf(claims.getSubject());
|
||||
|
||||
// 删除access token
|
||||
tokenCache.fastRemove(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
tokenCache = redissonClient.getMapCache(RedisKey.uid_access_token.getKey(), StringCodec.INSTANCE);
|
||||
}
|
||||
}
|
@@ -0,0 +1,137 @@
|
||||
package com.accompany.oauth.util;
|
||||
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.UUIDUtil;
|
||||
import com.accompany.oauth.config.OAuthConfig;
|
||||
import com.accompany.oauth.exception.OAuthException;
|
||||
import com.accompany.oauth.ticket.Ticket;
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import lombok.Getter;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JWT工具类 - 使用更安全的实现
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Component
|
||||
public class JwtUtil implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private OAuthConfig oAuthConfig;
|
||||
|
||||
@Getter
|
||||
private long accessTokenExpiration = 2592000;
|
||||
@Getter
|
||||
private long refreshTokenExpiration = 3196800;
|
||||
|
||||
private SecretKey secretKey;
|
||||
|
||||
/**
|
||||
* 生成访问令牌 (兼容OAuth2格式)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param now
|
||||
* @return JWT令牌
|
||||
*/
|
||||
public String generateAccessToken(Long userId, Date now) {
|
||||
Date expiration = getExpiration(now);
|
||||
|
||||
JwtBuilder builder = Jwts.builder()
|
||||
.setSubject(userId.toString())
|
||||
.setIssuedAt(now)
|
||||
.setExpiration(expiration)
|
||||
.claim("client_id", oAuthConfig.getClientId())
|
||||
.claim("token_type", "access_token")
|
||||
.claim("uid", userId) // 兼容OAuth2
|
||||
.claim("user_name", userId.toString()) // 兼容OAuth2
|
||||
.claim("authorities", "oauth2") // 兼容OAuth2
|
||||
.claim("jti", UUIDUtil.get()) // 兼容OAuth2
|
||||
.claim("scope", "read write")
|
||||
.signWith(secretKey, SignatureAlgorithm.HS256);
|
||||
|
||||
return builder.compact();
|
||||
}
|
||||
|
||||
public Date getExpiration(Date now){
|
||||
return new Date(now.getTime() + accessTokenExpiration * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成刷新令牌
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param now
|
||||
* @return JWT令牌
|
||||
*/
|
||||
public String generateRefreshToken(Long userId, Date now) {
|
||||
Date expiration = new Date(now.getTime() + refreshTokenExpiration * 1000);
|
||||
|
||||
return Jwts.builder()
|
||||
.setSubject(userId.toString())
|
||||
.setIssuedAt(now)
|
||||
.setExpiration(expiration)
|
||||
.claim("client_id", oAuthConfig.getClientId())
|
||||
.claim("token_type", "refresh_token")
|
||||
.signWith(secretKey, SignatureAlgorithm.HS256)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public String generateTicket(Ticket ticket, Long uid){
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("ticket_id", ticket.getValue());
|
||||
claims.put("client_id", oAuthConfig.getClientId());
|
||||
claims.put("exp", ticket.getExpiresIn());
|
||||
claims.put("uid", uid);
|
||||
claims.put("ticket_type", ticket.getTicketType());
|
||||
claims.put("scope", "read write");
|
||||
|
||||
Date now = new Date();
|
||||
Date expiration = ticket.getExpiration();
|
||||
|
||||
JwtBuilder builder = Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.setIssuedAt(now)
|
||||
.setExpiration(expiration)
|
||||
.signWith(secretKey, SignatureAlgorithm.HS256);
|
||||
|
||||
return builder.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证并解析JWT令牌
|
||||
*
|
||||
* @param token JWT令牌
|
||||
* @return Claims对象
|
||||
* @throws OAuthException 令牌无效或过期
|
||||
*/
|
||||
public Claims validateAndParseToken(String token) {
|
||||
try {
|
||||
return Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
} catch (ExpiredJwtException e) {
|
||||
throw new OAuthException(BusiStatus.ACCESS_TOKEN_HAS_EXPIRED);
|
||||
} catch (JwtException e) {
|
||||
throw new OAuthException(BusiStatus.INVALID_TOKEN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
// 确保密钥长度足够
|
||||
this.secretKey = Keys.hmacShaKeyFor(oAuthConfig.getJwtSignKey().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
45
accompany-oauth/accompany-oauth-web/pom.xml
Normal file
45
accompany-oauth/accompany-oauth-web/pom.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-oauth</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>accompany-oauth-web</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>OAuth Web模块 - 控制器和Web配置</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-oauth-service</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>com.accompany.oauth.OAuthApplication</mainClass>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<classifier>exec</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@@ -0,0 +1,47 @@
|
||||
package com.accompany.oauth;
|
||||
|
||||
import org.dromara.dynamictp.spring.annotation.EnableDynamicTp;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* OAuth应用程序启动类
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@EnableDynamicTp
|
||||
@SpringBootApplication
|
||||
@ComponentScan("com.accompany")
|
||||
@ComponentScan(basePackages = {
|
||||
"com.accompany.oauth", // OAuth模块
|
||||
"com.accompany.common", // 公共模块
|
||||
"com.accompany.core" // 核心模块
|
||||
})
|
||||
@MapperScan({"com.accompany.*.mapper","com.accompany.*.mybatismapper"})
|
||||
public class OAuthApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 设置系统属性
|
||||
System.setProperty("spring.application.name", "accompany-oauth");
|
||||
|
||||
SpringApplication app = new SpringApplication(OAuthApplication.class);
|
||||
|
||||
// 添加启动横幅
|
||||
app.setBanner((environment, sourceClass, out) -> {
|
||||
out.println();
|
||||
out.println(" ____ ");
|
||||
out.println(" / __ \\ ___ __ __ ___ __ __ ___ ___ ");
|
||||
out.println("/ /_/ / / / / V / / / / V / / / / / ");
|
||||
out.println("\\____/ /__/ /_/\\_/ /__/ /_/\\_/ /__/ /__/ ");
|
||||
out.println();
|
||||
out.println(":: Accompany OAuth Service :: (v1.0.0)");
|
||||
out.println(":: Powered by Spring Boot :: ");
|
||||
out.println();
|
||||
});
|
||||
|
||||
app.run(args);
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package com.accompany.oauth.config;
|
||||
|
||||
import com.accompany.oauth.dto.AuthResult;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* AuthResult自定义序列化器 - 直接输出OAuth2标准格式
|
||||
* 输出格式:{uid, access_token, token_type, expires_in, netEaseToken, userToken, loginKey, ...}
|
||||
* 直接兼容OAuth2的CustomOAuth2AccessToken格式
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@JsonComponent
|
||||
public class AuthResultJsonSerializer extends JsonSerializer<AuthResult> {
|
||||
|
||||
@Override
|
||||
public void serialize(AuthResult authResult, JsonGenerator gen, SerializerProvider serializers)
|
||||
throws IOException {
|
||||
|
||||
gen.writeStartObject();
|
||||
|
||||
// 标准OAuth字段
|
||||
gen.writeStringField("access_token", authResult.getAccessToken());
|
||||
gen.writeStringField("token_type", authResult.getTokenType());
|
||||
|
||||
if (authResult.getRefreshToken() != null) {
|
||||
gen.writeStringField("refresh_token", authResult.getRefreshToken());
|
||||
}
|
||||
|
||||
if (authResult.getExpiresIn() != null) {
|
||||
gen.writeNumberField("expires_in", authResult.getExpiresIn());
|
||||
}
|
||||
|
||||
if (authResult.getScope() != null) {
|
||||
gen.writeStringField("scope", authResult.getScope());
|
||||
}
|
||||
|
||||
// 用户ID (兼容oauth2)
|
||||
if (authResult.getUid() != null) {
|
||||
gen.writeNumberField("uid", authResult.getUid());
|
||||
}
|
||||
|
||||
// 网易云信Token (兼容oauth2)
|
||||
if (authResult.getNetEaseToken() != null && !authResult.getNetEaseToken().isEmpty()) {
|
||||
gen.writeStringField("netEaseToken", authResult.getNetEaseToken());
|
||||
}
|
||||
|
||||
// accid (兼容oauth2)
|
||||
if (authResult.getUid() != null) {
|
||||
gen.writeStringField("accid", authResult.getUid().toString());
|
||||
}
|
||||
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
package com.accompany.oauth.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.base.SpringContextHolder;
|
||||
import com.accompany.oauth.exception.OAuthException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
@ControllerAdvice
|
||||
public class OauthGlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 处理OAuth异常
|
||||
*
|
||||
* @param e OAuth异常
|
||||
* @return 错误响应
|
||||
*/
|
||||
@ExceptionHandler(OAuthException.class)
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> handleOAuthException(OAuthException e) {
|
||||
|
||||
BusiStatus status = e.getBusiStatus();
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("code", status.getCode());
|
||||
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
String i18nId = BusiStatus.class.getSimpleName() + StrUtil.DOT + status.getName();
|
||||
String abc = SpringContextHolder.getBean(MessageSource.class).getMessage(i18nId, null, status.getMessage(), locale);
|
||||
map.put("message", abc);
|
||||
|
||||
Map<String, String> additionalInformation = e.getAdditionalInformation();
|
||||
if (CollectionUtils.isEmpty(additionalInformation)){
|
||||
return ResponseEntity.status(status.getCode()).body(map);
|
||||
}
|
||||
for (String key : additionalInformation.keySet()){
|
||||
map.put(key, additionalInformation.get(key));
|
||||
}
|
||||
|
||||
return ResponseEntity.status(status.getCode()).body(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理参数异常
|
||||
*
|
||||
* @param e 参数异常
|
||||
* @return 错误响应
|
||||
*/
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> handleIllegalArgumentException(IllegalArgumentException e) {
|
||||
log.warn("参数异常: {}", e.getMessage());
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("error", "invalid_request");
|
||||
response.put("error_description", e.getMessage());
|
||||
response.put("timestamp", System.currentTimeMillis());
|
||||
|
||||
return ResponseEntity.badRequest().body(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理其他异常
|
||||
*
|
||||
* @param e 异常
|
||||
* @return 错误响应
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> handleException(Exception e) {
|
||||
log.error("系统异常", e);
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("error", "server_error");
|
||||
response.put("error_description", "系统内部错误");
|
||||
response.put("timestamp", System.currentTimeMillis());
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package com.accompany.oauth.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Web配置类
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 配置跨域
|
||||
*/
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOriginPatterns("*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.allowCredentials(true)
|
||||
.maxAge(3600);
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
package com.accompany.oauth.controller;
|
||||
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.core.base.DeviceInfoContextHolder;
|
||||
import com.accompany.oauth.dto.AuthResult;
|
||||
import com.accompany.oauth.service.AuthenticationService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 用户账户控制器
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/acc")
|
||||
public class AccountController {
|
||||
|
||||
@Autowired
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* 第三方登录 (兼容OAuth2格式)
|
||||
*
|
||||
* @param openId OpenID
|
||||
* @param type 第三方类型
|
||||
* @param unionId UnionID(可选)
|
||||
* @param idToken ID Token(可选)
|
||||
* @return 直接返回AuthResult结构
|
||||
*/
|
||||
@RequestMapping("/third/login")
|
||||
public BusiResult<AuthResult> thirdLogin(
|
||||
Byte type,
|
||||
@RequestParam("openid") String openId,
|
||||
@RequestParam("openid")String unionId,
|
||||
String idToken) {
|
||||
log.info("/acc/third/login? app {} , type {}, unionId {}", type, unionId);
|
||||
DeviceInfo deviceInfo = DeviceInfoContextHolder.get();
|
||||
AuthResult authResult = authenticationService.authenticateByThirdParty(type, openId, unionId, idToken, deviceInfo);
|
||||
return BusiResult.success(authResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注销 (兼容OAuth2格式)
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @return BusiResult响应结果
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public BusiResult<Void> logout(@RequestParam("access_token") String accessToken) {
|
||||
if (StringUtils.hasText(accessToken)) {
|
||||
authenticationService.revokeToken(accessToken);
|
||||
}
|
||||
return BusiResult.success();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
package com.accompany.oauth.controller;
|
||||
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.IPUtils;
|
||||
import com.accompany.core.base.DeviceInfoContextHolder;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.oauth.dto.AuthResult;
|
||||
import com.accompany.oauth.dto.TicketResponseVO;
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.oauth.service.AuthenticationService;
|
||||
import com.accompany.oauth.ticket.Ticket;
|
||||
import com.accompany.oauth.ticket.TicketService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* OAuth认证控制器
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/oauth")
|
||||
public class OAuthController {
|
||||
|
||||
@Autowired
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
@Autowired
|
||||
private TicketService ticketService;
|
||||
|
||||
/**
|
||||
* Token获取接口 - 简化实现 (兼容OAuth2格式)
|
||||
* 支持表单提交和JSON提交两种方式
|
||||
*
|
||||
* @param grantType 授权类型 (password, verify_code, email等)
|
||||
* @param password 密码
|
||||
* @param code 验证码
|
||||
* @return 直接返回AuthResult结构,兼容OAuth2的CustomOAuth2AccessToken
|
||||
*/
|
||||
@PostMapping("/token")
|
||||
public AuthResult token(@RequestParam(value = "grant_type") String grantType,
|
||||
@RequestParam(value = "username") String username,
|
||||
@RequestParam(value = "password") String password,
|
||||
@RequestParam(value = "phone") String phone,
|
||||
@RequestParam(value = "phoneAreaCode") String phoneAreaCode,
|
||||
@RequestParam(value = "email") String email,
|
||||
@RequestParam(value = "code") String code) {
|
||||
|
||||
// 1. 简单验证
|
||||
if (!StringUtils.hasText(grantType)) {
|
||||
throw new ServiceException(BusiStatus.PARAMERROR);
|
||||
}
|
||||
|
||||
// 2. 获取设备信息
|
||||
DeviceInfo deviceInfo = DeviceInfoContextHolder.get();
|
||||
|
||||
// 3. 直接调用服务,不做中间转换
|
||||
return authenticationService.authenticate(grantType,
|
||||
username, password, phone, phoneAreaCode, email, code, deviceInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ticket签发接口 - 简化实现 (兼容OAuth2格式)
|
||||
*
|
||||
* @param issueType 签发类型 (once/multi)
|
||||
* @param accessToken 访问令牌
|
||||
* @param httpRequest HTTP请求
|
||||
* @return BusiResult包装的Ticket响应
|
||||
*/
|
||||
@GetMapping("/ticket")
|
||||
public BusiResult<TicketResponseVO> issueTicket(@RequestParam("issue_type") String issueType,
|
||||
@RequestParam("access_token") String accessToken,
|
||||
HttpServletRequest httpRequest) {
|
||||
// 验证签发类型
|
||||
if (!Ticket.ONCE_TYPE.equals(issueType) && !Ticket.MULTI_TYPE.equals(issueType)) {
|
||||
throw new IllegalArgumentException("不支持的票据签发类型");
|
||||
}
|
||||
|
||||
DeviceInfo deviceInfo = DeviceInfoContextHolder.get();
|
||||
|
||||
// 直接传递accessToken给TicketService
|
||||
TicketResponseVO result = ticketService.issueTicket(accessToken);
|
||||
|
||||
// 获取IP地址并异步记录用户登录信息
|
||||
String ipAddress = IPUtils.getRealIpAddress(httpRequest);
|
||||
Long uid = result.getUid();
|
||||
ticketService.saveLoginRecord(uid, ipAddress, deviceInfo);
|
||||
|
||||
return BusiResult.success(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,149 @@
|
||||
package com.accompany.oauth.controller;
|
||||
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.DESUtils;
|
||||
import com.accompany.core.base.UidContextHolder;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Account;
|
||||
import com.accompany.core.service.account.AccountService;
|
||||
import com.accompany.core.util.KeyStore;
|
||||
import com.accompany.oauth.service.AccountManageService;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/acc/pwd")
|
||||
public class PwdController {
|
||||
|
||||
/** 密码强度检查正则,必须包括大小写字母和数字,长度为6到16 */
|
||||
private static final String PASSWORD_REGIX_V2 = "^(?=.*\\d)(?=.*[a-zA-Z]).{6,16}$";
|
||||
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
@Autowired
|
||||
private AccountManageService accountManageService;
|
||||
|
||||
/**
|
||||
* 重置密码接口,用于用户忘记密码,找回密码服务
|
||||
*
|
||||
* @param newPwd
|
||||
* 新密码
|
||||
* @param smsCode
|
||||
* 重置码
|
||||
* @return 1:成功 2:重置码无效 3:不存在该用户 4:其它错误
|
||||
*/
|
||||
@PostMapping("/reset")
|
||||
@SneakyThrows
|
||||
public BusiResult<Void> resetPassword(String phone, String newPwd, String smsCode) {
|
||||
if (StringUtils.isBlank(phone) || StringUtils.isBlank(newPwd) || StringUtils.isBlank(smsCode)){
|
||||
throw new ServiceException(BusiStatus.PARAMERROR);
|
||||
}
|
||||
|
||||
newPwd = DESUtils.DESAndBase64Decrypt(newPwd, KeyStore.DES_ENCRYPT_KEY);
|
||||
|
||||
// 密码长度检查
|
||||
if(!newPwd.matches(PASSWORD_REGIX_V2)){
|
||||
return new BusiResult<>(BusiStatus.WEAK_PASSWORD);
|
||||
}
|
||||
|
||||
Long uid = UidContextHolder.get();
|
||||
phone = DESUtils.DESAndBase64Decrypt(phone, KeyStore.DES_ENCRYPT_KEY);
|
||||
|
||||
accountManageService.resetPasswordByResetCode(uid, phone, newPwd, smsCode);
|
||||
|
||||
return new BusiResult<>(BusiStatus.SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码接口,用于用户忘记密码,找回密码服务
|
||||
*
|
||||
* @param newPwd
|
||||
* 新密码
|
||||
* @param email
|
||||
* 邮箱
|
||||
* @return 1:成功 2:重置码无效 3:不存在该用户 4:其它错误
|
||||
*/
|
||||
@PostMapping("/resetByEmail")
|
||||
@SneakyThrows
|
||||
public BusiResult<Void> resetPasswordByEmail(String email, String newPwd, String code) {
|
||||
if (StringUtils.isBlank(email) || StringUtils.isBlank(newPwd) || StringUtils.isBlank(code)){
|
||||
throw new ServiceException(BusiStatus.PARAMERROR);
|
||||
}
|
||||
|
||||
Long uid = UidContextHolder.get();
|
||||
email = DESUtils.DESAndBase64Decrypt(email, KeyStore.DES_ENCRYPT_KEY);
|
||||
newPwd = DESUtils.DESAndBase64Decrypt(newPwd, KeyStore.DES_ENCRYPT_KEY);
|
||||
|
||||
// 密码长度检查
|
||||
if(!newPwd.matches(PASSWORD_REGIX_V2)){
|
||||
return new BusiResult<>(BusiStatus.WEAK_PASSWORD);
|
||||
}
|
||||
|
||||
accountManageService.resetPasswordByEmailCode(uid, email, newPwd, code);
|
||||
|
||||
return new BusiResult<>(BusiStatus.SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置新密码
|
||||
* @param newPwd
|
||||
* @return
|
||||
*/
|
||||
@Authorization
|
||||
@PostMapping("/set")
|
||||
@SneakyThrows
|
||||
public BusiResult<Void> setupPassword(String newPwd) {
|
||||
//加入密码DES解密
|
||||
newPwd = DESUtils.DESAndBase64Decrypt(newPwd, KeyStore.DES_ENCRYPT_KEY);
|
||||
|
||||
// 密码长度检查
|
||||
if(!newPwd.matches(PASSWORD_REGIX_V2)){
|
||||
return new BusiResult<>(BusiStatus.WEAK_PASSWORD);
|
||||
}
|
||||
|
||||
Long uid = UidContextHolder.get();
|
||||
|
||||
accountManageService.setupInitialPassword(uid, newPwd);
|
||||
|
||||
return new BusiResult<>(BusiStatus.SUCCESS);
|
||||
}
|
||||
|
||||
@Authorization
|
||||
@PostMapping("/modify")
|
||||
@SneakyThrows
|
||||
public BusiResult<Void> modifyPassword(HttpServletRequest request,
|
||||
String pwd, String newPwd) {
|
||||
|
||||
newPwd = DESUtils.DESAndBase64Decrypt(newPwd, KeyStore.DES_ENCRYPT_KEY);
|
||||
|
||||
// 密码长度检查
|
||||
if(!newPwd.matches(PASSWORD_REGIX_V2)){
|
||||
return new BusiResult<>(BusiStatus.WEAK_PASSWORD);
|
||||
}
|
||||
|
||||
Long uid = UidContextHolder.get();
|
||||
|
||||
// 加入密码DES解密
|
||||
pwd = DESUtils.DESAndBase64Decrypt(pwd, KeyStore.DES_ENCRYPT_KEY);
|
||||
|
||||
Account account = this.accountService.getById(uid);
|
||||
if (account == null) {
|
||||
return new BusiResult<>(BusiStatus.INVALID_USER);
|
||||
}
|
||||
|
||||
accountManageService.resetPasswordByOldPassword(account.getPhone(), pwd, newPwd);
|
||||
|
||||
return new BusiResult<>(BusiStatus.SUCCESS);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
#MySQL数据库配置
|
||||
spring:
|
||||
dynamic-datasource:
|
||||
master:
|
||||
poolName: master
|
||||
jdbcUrl: jdbc:mysql://124.156.164.187:3306/peko?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&tinyInt1isBit=false&useSSL=false&useCursorFetch=true
|
||||
username: root
|
||||
password: anan@dev##
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
hikari:
|
||||
minimum-idle: 10
|
||||
maximum-pool-size: 20
|
||||
connection-test-query: select 1
|
||||
max-lifetime: 7000
|
||||
slave:
|
||||
poolName: slave
|
||||
jdbcUrl: jdbc:mysql://124.156.164.187:3306/peko?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&tinyInt1isBit=false&useSSL=false&useCursorFetch=true
|
||||
username: root
|
||||
password: anan@dev##
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
hikari:
|
||||
minimum-idle: 10
|
||||
maximum-pool-size: 20
|
||||
connection-test-query: select 1
|
||||
max-lifetime: 7000
|
||||
redis:
|
||||
host: 124.156.164.187
|
||||
port: 6200
|
||||
maxTotal: 100
|
||||
maxIdle: 50
|
||||
maxWait: 2500
|
||||
testOnBorrow: true
|
||||
testOnReturn: true
|
||||
password: anan@dev@redis@#!
|
||||
redisson:
|
||||
# file: classpath:redisson.yaml
|
||||
config: |
|
||||
singleServerConfig:
|
||||
address: redis://124.156.164.187:6200
|
||||
password: anan@dev@redis@#!
|
||||
connectionMinimumIdleSize: 4
|
||||
timeout: 10000
|
||||
threads: 8
|
||||
nettyThreads: 16
|
||||
codec: !<org.redisson.codec.JsonJacksonCodec> {}
|
||||
transportMode: "NIO"
|
||||
|
||||
## rocketmq 配置
|
||||
rocketmq:
|
||||
name-server: 124.156.164.187:9876
|
||||
producer:
|
||||
group: peko-group
|
||||
sendMessageTimeout: 300000
|
||||
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
oauth2:
|
||||
server:
|
||||
clientId: erban-client
|
||||
clientSecret: uyzjdhds
|
||||
jwtSignKey: ead18800082c5807806d8f54914f84f4fa360dd568f4784288a4439b5fee0f25
|
@@ -0,0 +1,83 @@
|
||||
spring:
|
||||
application:
|
||||
name: oauth
|
||||
profiles:
|
||||
active: native
|
||||
main:
|
||||
allow-bean-definition-overriding : true
|
||||
allow-circular-references: true
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ant_path_matcher
|
||||
|
||||
---
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: native
|
||||
cloud:
|
||||
nacos:
|
||||
config:
|
||||
server-addr: 124.156.164.187:8848
|
||||
namespace: 5edc3246-3e69-4be5-a32a-273f0a09ddf6
|
||||
file-extension: yml
|
||||
shared-configs:
|
||||
- data-id: application.yml
|
||||
refresh: true
|
||||
- data-id: thirdpart.yml
|
||||
refresh: true
|
||||
- data-id: pay.yml
|
||||
refresh: true
|
||||
- data-id: sysconf.yml
|
||||
refresh: true
|
||||
- data-id: dtp.yml
|
||||
refresh: true
|
||||
|
||||
---
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: dev
|
||||
cloud:
|
||||
nacos:
|
||||
config:
|
||||
server-addr: 124.156.164.187:8848
|
||||
namespace: 5edc3246-3e69-4be5-a32a-273f0a09ddf6
|
||||
file-extension: yml
|
||||
shared-configs:
|
||||
- data-id: application.yml
|
||||
refresh: true
|
||||
- data-id: thirdpart.yml
|
||||
refresh: true
|
||||
- data-id: pay.yml
|
||||
refresh: true
|
||||
- data-id: sysconf.yml
|
||||
refresh: true
|
||||
- data-id: dtp.yml
|
||||
refresh: true
|
||||
- data-id: database.yml
|
||||
refresh: true
|
||||
---
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: prod
|
||||
cloud:
|
||||
nacos:
|
||||
config:
|
||||
server-addr: 172.19.16.15:8848
|
||||
namespace: 0c9bf047-19ca-4969-bf5d-bbc1f86b501a
|
||||
file-extension: yml
|
||||
shared-configs:
|
||||
- data-id: application.yml
|
||||
refresh: true
|
||||
- data-id: thirdpart.yml
|
||||
refresh: true
|
||||
- data-id: pay.yml
|
||||
refresh: true
|
||||
- data-id: sysconf.yml
|
||||
refresh: true
|
||||
- data-id: threadpool.yml
|
||||
refresh: true
|
||||
- data-id: database.yml
|
||||
refresh: true
|
@@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds">
|
||||
<!--引入默认的一些设置-->
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
<!--web信息-->
|
||||
<logger name="org.springframework.web" level="info"/>
|
||||
|
||||
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
|
||||
<property name="LOG_HOME" value="/data/java/weblog/accompany-oauth"/>
|
||||
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%X{trace_uuid}] %-5level %logger{36} %line - %msg%n" />
|
||||
|
||||
<!--写入日志到控制台的appender,用默认的,但是要去掉charset,否则windows下tomcat下乱码-->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="info_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/web_info.log</file>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/rolling/web_info.%d{yyyy-MM-dd}.%i.log.gz
|
||||
</fileNamePattern>
|
||||
<maxHistory>90</maxHistory>
|
||||
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>256MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="warn_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/web_warn.log</file>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>WARN</level>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/rolling/web_warn_.%d{yyyy-MM-dd}.%i.log.gz
|
||||
</fileNamePattern>
|
||||
<maxHistory>90</maxHistory>
|
||||
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>256MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="error_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/web_error.log</file>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>ERROR</level>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/rolling/web_error_.%d{yyyy-MM-dd}.%i.log.gz
|
||||
</fileNamePattern>
|
||||
<maxHistory>90</maxHistory>
|
||||
<cleanHistoryOnStart>true</cleanHistoryOnStart>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>256MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!--异步到文件-->
|
||||
<appender name="info_async_file" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>512</queueSize>
|
||||
<appender-ref ref="info_file"/>
|
||||
</appender>
|
||||
|
||||
<appender name ="warn_async_file" class= "ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>512</queueSize>
|
||||
<includeCallerData>false</includeCallerData>
|
||||
<appender-ref ref ="warn_file"/>
|
||||
</appender>
|
||||
|
||||
<appender name ="error_async_file" class= "ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>512</queueSize>
|
||||
<includeCallerData>false</includeCallerData>
|
||||
<appender-ref ref ="error_file"/>
|
||||
</appender>
|
||||
|
||||
<!--生产环境:打印控制台和输出到文件-->
|
||||
<springProfile name="prod">
|
||||
<root level="info">
|
||||
<appender-ref ref="info_async_file"/>
|
||||
<appender-ref ref="warn_async_file"/>
|
||||
<appender-ref ref="error_async_file"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
<!--开发环境:打印控制台-->
|
||||
<springProfile name="dev">
|
||||
<logger name="com.accompany" level="DEBUG"/>
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="info_async_file"/>
|
||||
<appender-ref ref="warn_async_file"/>
|
||||
<appender-ref ref="error_async_file"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="native">
|
||||
<logger name="com.accompany" level="DEBUG"/>
|
||||
<root level="info">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="info_async_file"/>
|
||||
<appender-ref ref="warn_async_file"/>
|
||||
<appender-ref ref="error_async_file"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
@@ -0,0 +1,155 @@
|
||||
package com.accompany.oauth.integration;
|
||||
|
||||
import com.accompany.oauth.dto.AuthResult;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* OAuth2兼容性集成测试
|
||||
* 验证OAuth模块与OAuth2模块的API兼容性
|
||||
*
|
||||
* @author Accompany OAuth Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
public class OAuth2CompatibilityTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 测试密码认证端点兼容性 (表单格式)
|
||||
*/
|
||||
@Test
|
||||
public void testPasswordAuthenticationForm() throws Exception {
|
||||
MvcResult result = mockMvc.perform(post("/oauth/token")
|
||||
.param("grant_type", "password")
|
||||
.param("phone", "13800138000")
|
||||
.param("password", "123456")
|
||||
.param("client_id", "erban-client")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").exists())
|
||||
.andExpect(jsonPath("$.token_type").value("Bearer"))
|
||||
.andExpect(jsonPath("$.expires_in").exists())
|
||||
.andExpect(jsonPath("$.uid").exists())
|
||||
.andReturn();
|
||||
|
||||
String responseJson = result.getResponse().getContentAsString();
|
||||
AuthResult authResult = objectMapper.readValue(responseJson, AuthResult.class);
|
||||
|
||||
// 验证OAuth2兼容字段
|
||||
assertNotNull(authResult.getAccessToken());
|
||||
assertEquals("Bearer", authResult.getTokenType());
|
||||
assertNotNull(authResult.getExpiresIn());
|
||||
assertNotNull(authResult.getUid());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试验证码认证端点兼容性
|
||||
*/
|
||||
@Test
|
||||
public void testVerifyCodeAuthentication() throws Exception {
|
||||
mockMvc.perform(post("/oauth/token")
|
||||
.param("grant_type", "verify_code")
|
||||
.param("phone", "13800138000")
|
||||
.param("code", "888888")
|
||||
.param("client_id", "erban-client")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").exists())
|
||||
.andExpect(jsonPath("$.token_type").value("Bearer"))
|
||||
.andExpect(jsonPath("$.uid").exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试邮箱认证端点兼容性
|
||||
*/
|
||||
@Test
|
||||
public void testEmailAuthentication() throws Exception {
|
||||
mockMvc.perform(post("/oauth/token")
|
||||
.param("grant_type", "email")
|
||||
.param("email", "test@example.com")
|
||||
.param("code", "666666")
|
||||
.param("client_id", "erban-client")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").exists())
|
||||
.andExpect(jsonPath("$.token_type").value("Bearer"))
|
||||
.andExpect(jsonPath("$.uid").exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试Token响应格式兼容性
|
||||
* 确保返回的JSON结构与OAuth2的CustomOAuth2AccessToken一致
|
||||
*/
|
||||
@Test
|
||||
public void testTokenResponseFormat() throws Exception {
|
||||
MvcResult result = mockMvc.perform(post("/oauth/token")
|
||||
.param("grant_type", "password")
|
||||
.param("phone", "13800138000")
|
||||
.param("password", "123456")
|
||||
.param("client_id", "erban-client")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
String responseJson = result.getResponse().getContentAsString();
|
||||
|
||||
// 验证JSON包含所有OAuth2字段
|
||||
assertTrue(responseJson.contains("access_token"));
|
||||
assertTrue(responseJson.contains("token_type"));
|
||||
assertTrue(responseJson.contains("expires_in"));
|
||||
assertTrue(responseJson.contains("scope"));
|
||||
assertTrue(responseJson.contains("uid"));
|
||||
assertTrue(responseJson.contains("netEaseToken"));
|
||||
|
||||
// 验证结构与OAuth2兼容
|
||||
AuthResult authResult = objectMapper.readValue(responseJson, AuthResult.class);
|
||||
assertNotNull(authResult.getAccessToken());
|
||||
assertEquals("Bearer", authResult.getTokenType());
|
||||
assertNotNull(authResult.getUid());
|
||||
assertNotNull(authResult.getNetEaseToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用户注销端点兼容性
|
||||
*/
|
||||
@Test
|
||||
public void testLogoutCompatibility() throws Exception {
|
||||
// 先获取token
|
||||
MvcResult loginResult = mockMvc.perform(post("/oauth/token")
|
||||
.param("grant_type", "password")
|
||||
.param("phone", "13800138000")
|
||||
.param("password", "123456")
|
||||
.param("client_id", "erban-client")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
String responseJson = loginResult.getResponse().getContentAsString();
|
||||
AuthResult authResult = objectMapper.readValue(responseJson, AuthResult.class);
|
||||
|
||||
// 测试注销
|
||||
mockMvc.perform(post("/acc/logout")
|
||||
.param("access_token", authResult.getAccessToken())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(200))
|
||||
.andExpect(jsonPath("$.message").value("success"));
|
||||
}
|
||||
}
|
21
accompany-oauth/pom.xml
Normal file
21
accompany-oauth/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.accompany</groupId>
|
||||
<artifactId>accompany-dependencies</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../accompany-dependencies</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>accompany-oauth</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>accompany-oauth-sdk</module>
|
||||
<module>accompany-oauth-service</module>
|
||||
<module>accompany-oauth-web</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
@@ -67,8 +67,7 @@ public class JwtTicketConverter implements TicketEnhancer,TicketCoverter {
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot convert access token to JSON", e);
|
||||
}
|
||||
String token = JwtHelper.encode(content, signer).getEncoded();
|
||||
return token;
|
||||
return JwtHelper.encode(content, signer).getEncoded();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ package com.accompany.oauth2.jwt;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.core.service.common.JedisService;
|
||||
import com.accompany.oauth2.model.AccountDetails;
|
||||
import com.accompany.oauth2.service.account.AccountH5LoginService;
|
||||
import com.accompany.oauth2.token.CustomOAuth2AccessToken;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -18,9 +17,6 @@ public class JwtTokenConverter extends JwtAccessTokenConverter {
|
||||
@Autowired
|
||||
private JedisService jedisService;
|
||||
|
||||
@Autowired
|
||||
private AccountH5LoginService accountH5LoginService;
|
||||
|
||||
@Override
|
||||
public CustomOAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
|
||||
accessToken = super.enhance(accessToken, authentication);
|
||||
|
@@ -1,107 +0,0 @@
|
||||
package com.accompany.oauth2.service.account;
|
||||
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.base.SpringContextHolder;
|
||||
import com.accompany.core.enumeration.PartitionEnum;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Users;
|
||||
import com.accompany.core.mybatismapper.AccountLoginRecordMapperExpand;
|
||||
import com.accompany.core.service.common.JedisService;
|
||||
import com.accompany.core.service.user.UsersBaseService;
|
||||
import com.accompany.core.util.JwtUtils;
|
||||
import com.accompany.oauth2.support.h5.H5TokenGranter;
|
||||
import com.accompany.oauth2.token.H5AccessToken;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by yuanyi on 2019/2/21.
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AccountH5LoginService {
|
||||
|
||||
private static final long H5_JWT_TOKEN_EX = 60 * 60 * 1000 * 2L;
|
||||
|
||||
@Autowired
|
||||
private UsersBaseService usersBaseService;
|
||||
@Autowired
|
||||
private AccountLoginRecordMapperExpand accountLoginRecordMapperExpand;
|
||||
@Autowired
|
||||
private JedisService jedisService;
|
||||
@Autowired
|
||||
private JwtUtils jwtUtils;
|
||||
|
||||
public String createJwtToken(Long uid) {
|
||||
return jwtUtils.createJWT(H5_JWT_TOKEN_EX, uid);
|
||||
}
|
||||
|
||||
private void saveH5LoginJwtToken(Long uid, String jwtToken) {
|
||||
jedisService.hset(RedisKey.h5loginjwtoken.getKey(), uid.toString(), jwtToken);
|
||||
}
|
||||
|
||||
private void deleteH5LoginJwtToken(Long uid) {
|
||||
jedisService.hdel(RedisKey.h5loginjwtoken.getKey(), uid.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建h5令牌
|
||||
*
|
||||
* @param uid
|
||||
* @return
|
||||
*/
|
||||
public H5AccessToken createH5AccessToken(Long uid) {
|
||||
//限制只是华语区
|
||||
Users u = usersBaseService.getUsersByUid(uid);
|
||||
if (null == u){
|
||||
throw new ServiceException(BusiStatus.USERNOTEXISTS);
|
||||
}
|
||||
|
||||
if (u.getPartitionId() != PartitionEnum.CHINESE.getId()) {
|
||||
Integer userCount = usersBaseService.rechargeUserCount(uid);
|
||||
if (userCount <= 0) {
|
||||
throw new ServiceException(BusiStatus.H5_RECHARGE_USER_NOT_OPEN);
|
||||
}
|
||||
}
|
||||
|
||||
String jwtToken = createJwtToken(uid);
|
||||
saveH5LoginJwtToken(uid, jwtToken);
|
||||
H5AccessToken accessToken = new H5AccessToken();
|
||||
accessToken.setPartitionId(u.getPartitionId());
|
||||
accessToken.setAccess_token(jwtToken);
|
||||
accessToken.setUid(uid);
|
||||
accessToken.setExpires_in(H5_JWT_TOKEN_EX);
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public H5AccessToken token(ServletWebRequest request) {
|
||||
String grantType = request.getParameter("grant_type");
|
||||
Map<String, H5TokenGranter> tokenGranterMap = SpringContextHolder.getApplicationContext().getBeansOfType(H5TokenGranter.class);
|
||||
for (H5TokenGranter tokenGranter : tokenGranterMap.values()) {
|
||||
if (tokenGranter.getGrantType().equals(grantType)) {
|
||||
H5AccessToken token = tokenGranter.getAuthentication(request);
|
||||
if (token != null) {
|
||||
Long uid = token.getUid();
|
||||
Integer isExists = accountLoginRecordMapperExpand.isExists(uid);
|
||||
if (isExists > 0) {
|
||||
deleteH5LoginJwtToken(uid);
|
||||
throw new ServiceException(BusiStatus.REGION_NOT_OPEN_UP);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
package com.accompany.oauth2.support.h5;
|
||||
|
||||
import com.accompany.oauth2.token.H5AccessToken;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: liaozetao
|
||||
* @date: 2023/7/17 10:25
|
||||
* @description:
|
||||
*/
|
||||
public abstract class AbstractH5TokenGranter implements H5TokenGranter {
|
||||
|
||||
protected static final String PHONE_AREA_CODE = "phoneAreaCode";
|
||||
|
||||
protected static final String PHONE = "phone";
|
||||
|
||||
protected static final String PASSWORD = "password";
|
||||
|
||||
protected static final String CODE = "code";
|
||||
|
||||
private final String grantType;
|
||||
|
||||
public AbstractH5TokenGranter(String grantType) {
|
||||
this.grantType = grantType;
|
||||
}
|
||||
|
||||
public H5AccessToken getAuthentication(ServletWebRequest request) {
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String[] value = entry.getValue();
|
||||
if (value.length > 0) {
|
||||
parameters.put(key, value[0]);
|
||||
}
|
||||
}
|
||||
return authenticate(parameters);
|
||||
}
|
||||
|
||||
public abstract H5AccessToken authenticate(Map<String, Object> parameters);
|
||||
|
||||
public String getGrantType() {
|
||||
return grantType;
|
||||
}
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
package com.accompany.oauth2.support.h5;
|
||||
|
||||
import com.accompany.oauth2.token.H5AccessToken;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
/**
|
||||
* @author: liaozetao
|
||||
* @date: 2023/7/17 12:16
|
||||
* @description:
|
||||
*/
|
||||
public interface H5TokenGranter {
|
||||
|
||||
/**
|
||||
* 获取令牌
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
H5AccessToken getAuthentication(ServletWebRequest request);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getGrantType();
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
package com.accompany.oauth2.support.h5;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.common.utils.DESUtils;
|
||||
import com.accompany.core.util.KeyStore;
|
||||
import com.accompany.core.util.MD5;
|
||||
import com.accompany.oauth2.constant.GrantTypeEnum;
|
||||
import com.accompany.oauth2.constant.LoginTypeEnum;
|
||||
import com.accompany.oauth2.model.AccountDetails;
|
||||
import com.accompany.oauth2.service.MyUserDetailsService;
|
||||
import com.accompany.oauth2.service.account.AccountH5LoginService;
|
||||
import com.accompany.oauth2.token.H5AccessToken;
|
||||
import com.accompany.oauth2.util.RequestContextHolderUtils;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: liaozetao
|
||||
* @date: 2023/7/17 10:37
|
||||
* @description:
|
||||
*/
|
||||
@Slf4j
|
||||
public class PasswordH5TokenGranter extends AbstractH5TokenGranter {
|
||||
|
||||
private final MyUserDetailsService userDetailsService;
|
||||
|
||||
private final AccountH5LoginService accountH5LoginService;
|
||||
|
||||
public PasswordH5TokenGranter(MyUserDetailsService userDetailsService, AccountH5LoginService accountH5LoginService) {
|
||||
super(GrantTypeEnum.PASSWORD.getValue());
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.accountH5LoginService = accountH5LoginService;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public H5AccessToken authenticate(Map<String, Object> parameters) {
|
||||
String phoneAreaCode = StrUtil.toString(parameters.get(PHONE_AREA_CODE));
|
||||
String username = StrUtil.toString(parameters.get(PHONE));
|
||||
String password = StrUtil.toString(parameters.get(PASSWORD));
|
||||
String code = StrUtil.toString(parameters.get(CODE));
|
||||
String ipAddress = RequestContextHolderUtils.getRemoteAddr();
|
||||
DeviceInfo deviceInfo = new DeviceInfo();
|
||||
try {
|
||||
BeanUtils.populate(deviceInfo, parameters);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
UserDetails userDetails;
|
||||
try {
|
||||
username = DESUtils.DESAndBase64Decrypt(username, KeyStore.DES_ENCRYPT_KEY);
|
||||
userDetails = userDetailsService.loadUserByPhone(username, phoneAreaCode, code, deviceInfo, ipAddress);
|
||||
try {
|
||||
password = MD5.getMD5(DESUtils.DESAndBase64Decrypt(password, KeyStore.DES_ENCRYPT_KEY));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("密码非法");
|
||||
}
|
||||
userDetailsService.handlePwdLogin(username, password, userDetails);
|
||||
userDetailsService.login(username, userDetails, LoginTypeEnum.PASSWORD, deviceInfo, code);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
return accountH5LoginService.createH5AccessToken(((AccountDetails) userDetails).getAccount().getUid());
|
||||
}
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
package com.accompany.oauth2.support.h5;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.accompany.common.device.DeviceInfo;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.core.service.user.PhoneBlackService;
|
||||
import com.accompany.oauth2.constant.GrantTypeEnum;
|
||||
import com.accompany.oauth2.constant.LoginTypeEnum;
|
||||
import com.accompany.oauth2.exception.CustomOAuth2Exception;
|
||||
import com.accompany.oauth2.model.AccountDetails;
|
||||
import com.accompany.oauth2.service.MyUserDetailsService;
|
||||
import com.accompany.oauth2.service.account.AccountH5LoginService;
|
||||
import com.accompany.oauth2.token.H5AccessToken;
|
||||
import com.accompany.oauth2.util.RequestContextHolderUtils;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: liaozetao
|
||||
* @date: 2023/7/17 10:38
|
||||
* @description:
|
||||
*/
|
||||
@Slf4j
|
||||
public class VerifyCodeH5TokenGranter extends AbstractH5TokenGranter {
|
||||
|
||||
private final MyUserDetailsService userDetailsService;
|
||||
|
||||
private final PhoneBlackService phoneBlackService;
|
||||
|
||||
private final AccountH5LoginService accountH5LoginService;
|
||||
|
||||
public VerifyCodeH5TokenGranter(MyUserDetailsService userDetailsService, PhoneBlackService phoneBlackService, AccountH5LoginService accountH5LoginService) {
|
||||
super(GrantTypeEnum.VERIFY_CODE.getValue());
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.phoneBlackService = phoneBlackService;
|
||||
this.accountH5LoginService = accountH5LoginService;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public H5AccessToken authenticate(Map<String, Object> parameters) {
|
||||
String phoneAreaCode = StrUtil.toString(parameters.get(PHONE_AREA_CODE));
|
||||
String phone = StrUtil.toString(parameters.get(PHONE));
|
||||
String code = StrUtil.toString(parameters.get(CODE));
|
||||
DeviceInfo deviceInfo = new DeviceInfo();
|
||||
try {
|
||||
BeanUtils.populate(deviceInfo, parameters);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
if (phoneBlackService.checkIsNeedIntercept(phone)) {
|
||||
throw new CustomOAuth2Exception(CustomOAuth2Exception.PHONE_BE_INTERCEPTED, BusiStatus.PHONE_BE_INTERCEPTED.getReasonPhrase());
|
||||
}
|
||||
UserDetails userDetails = null;
|
||||
try {
|
||||
userDetails = userDetailsService.loadUserByPhone(phone, phoneAreaCode, code, deviceInfo, RequestContextHolderUtils.getRemoteAddr());
|
||||
userDetailsService.login(phone, userDetails, LoginTypeEnum.ID, deviceInfo, code);
|
||||
} catch (CustomOAuth2Exception e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
return accountH5LoginService.createH5AccessToken(((AccountDetails) userDetails).getAccount().getUid());
|
||||
}
|
||||
}
|
@@ -19,9 +19,6 @@ public class H5AccessToken {
|
||||
@ApiModelProperty("用户ID")
|
||||
private Long uid;
|
||||
|
||||
@ApiModelProperty("分区id")
|
||||
private Integer partitionId;
|
||||
|
||||
/**
|
||||
* 令牌
|
||||
*/
|
||||
|
@@ -4,11 +4,7 @@ import com.accompany.core.service.SysConfService;
|
||||
import com.accompany.core.service.user.PhoneBlackService;
|
||||
import com.accompany.oauth2.service.MyUserDetailsService;
|
||||
import com.accompany.oauth2.service.MyUserDetailsServiceImpl;
|
||||
import com.accompany.oauth2.service.account.AccountH5LoginService;
|
||||
import com.accompany.oauth2.support.email.EmailAuthenticationProvider;
|
||||
import com.accompany.oauth2.support.h5.H5TokenGranter;
|
||||
import com.accompany.oauth2.support.h5.PasswordH5TokenGranter;
|
||||
import com.accompany.oauth2.support.h5.VerifyCodeH5TokenGranter;
|
||||
import com.accompany.oauth2.support.password.PasswordAuthenticationProvider;
|
||||
import com.accompany.oauth2.support.verify.VerifyCodeAuthenticationProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -34,9 +30,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private PhoneBlackService phoneBlackService;
|
||||
|
||||
@Autowired
|
||||
private AccountH5LoginService accountH5LoginService;
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
protected UserDetailsService userDetailsService() {
|
||||
@@ -90,13 +83,4 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
return new EmailAuthenticationProvider(myUserDetailsService());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public H5TokenGranter passwordH5TokenGranter() {
|
||||
return new PasswordH5TokenGranter(myUserDetailsService(), accountH5LoginService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public H5TokenGranter verifyCodeH5TokenGranter() {
|
||||
return new VerifyCodeH5TokenGranter(myUserDetailsService(), phoneBlackService, accountH5LoginService);
|
||||
}
|
||||
}
|
||||
|
@@ -1,47 +0,0 @@
|
||||
package com.accompany.oauth2.controller;
|
||||
|
||||
import com.accompany.common.result.BusiResult;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.oauth2.common.BaseController;
|
||||
import com.accompany.oauth2.service.account.AccountH5LoginService;
|
||||
import com.accompany.oauth2.token.H5AccessToken;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Created by yuanyi on 2019/2/22.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/oauth/h5")
|
||||
public class H5LoginController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private AccountH5LoginService accountH5LoginService;
|
||||
|
||||
/**
|
||||
* 授权登录
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation("授权登录")
|
||||
@PostMapping("/token")
|
||||
public BusiResult<H5AccessToken> token(HttpServletRequest request, HttpServletResponse response) {
|
||||
try {
|
||||
return BusiResult.success(accountH5LoginService.token(new ServletWebRequest(request, response)));
|
||||
} catch (ServiceException e) {
|
||||
return BusiResult.fail(e.getBusiStatus(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user