| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- package com.tzy.service.impl;
- import com.tzy.common.exception.ServiceException;
- import com.tzy.common.utils.UserType;
- import com.tzy.dto.AccountProfileInfoDTO;
- import com.tzy.dto.EndUserDTO;
- import com.tzy.entity.AppAccount;
- import com.tzy.entity.AppBaseUser;
- import com.tzy.mapper.PoyeeAppAccountMapper;
- import com.tzy.mapper.PoyeeAppBaseUserMapper;
- import com.tzy.req.*;
- import com.tzy.service.AppAccountOidcService;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.StringUtils;
- import javax.annotation.Resource;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.ZoneId;
- import java.util.Collections;
- import java.util.Date;
- import java.util.List;
- @Service
- public class AppAccountOidcServiceImpl implements AppAccountOidcService {
- private static final String ACTIVE = "ACTIVE";
- private static final String INACTIVE = "INACTIVE";
- private static final String BANNED = "BANNED";
- private static final String DEFAULT_AVATAR = "https://static.public.hobbystock.cn/applet/share/share_logo2.png";
- private static final int DEFAULT_ROLE_ID = 0;
- private static final SecureRandom SECURE_RANDOM = new SecureRandom();
- @Resource
- private PoyeeAppAccountMapper poyeeAppAccountMapper;
- @Resource
- private PoyeeAppBaseUserMapper poyeeAppBaseUserMapper;
- public AppAccountOidcServiceImpl() {
- }
- public AppAccountOidcServiceImpl(PoyeeAppAccountMapper appAccountMapper, PoyeeAppBaseUserMapper appBaseUserMapper) {
- this.poyeeAppAccountMapper = appAccountMapper;
- this.poyeeAppBaseUserMapper = appBaseUserMapper;
- }
- @Override
- public EndUserDTO loadUserByLoginId(String loginId) {
- if (!StringUtils.hasText(loginId)) {
- return null;
- }
- AppAccount account = poyeeAppAccountMapper.selectByLoginId(loginId);
- AppBaseUser baseUser;
- if (account == null) {
- baseUser = poyeeAppBaseUserMapper.selectByExternalLoginId(loginId);
- if (baseUser == null) {
- return null;
- }
- account = poyeeAppAccountMapper.selectByLoginId(baseUser.getUsername());
- } else {
- baseUser = poyeeAppBaseUserMapper.selectByUsername(account.getAccount());
- }
- return toEndUser(loginId, account, baseUser);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public EndUserDTO createEmailUser(EmailCreateRequest request) {
- String email = request == null ? null : request.getEmail();
- String displayName = request != null && request.getDisplayName() != null && request.getDisplayName().isPresent()
- ? request.getDisplayName().get() : null;
- return createUser(email, null, email, null, null, displayName, null, "EMAIL", null);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public EndUserDTO createEmailPasswordUser(EmailPasswordCreateRequest request) {
- if (request == null) {
- throw new ServiceException("参数不能为空");
- }
- return createUser(request.getEmail(), null, request.getEmail(), request.getPassword(), null,
- request.getDisplayName(), null, "EMAIL_PASSWORD", null);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public EndUserDTO createPhoneUser(PhoneCreateRequest request) {
- if (request == null || !StringUtils.hasText(request.getPhone())) {
- throw new ServiceException("参数不能为空");
- }
- String phone = request.getPhone().trim();
- return createUser(phone, phone, null, null, null, null, null, resolvePhoneRegisterChannel(request), null);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public EndUserDTO createWeChatUser(WeChatCreateRequest request) {
- if (request == null) {
- throw new ServiceException("参数不能为空");
- }
- return createUser(request.getOpenId(), null, null, null, request.getOpenId(),
- request.getNickName(), request.getAvatarUrl(), "WECHAT_AUTH", null);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public EndUserDTO createWeChatPhoneUser(WeChatPhoneCreateRequest request) {
- if (request == null) {
- throw new ServiceException("参数不能为空");
- }
- return createUser(request.getPhone(), request.getPhone(), null, null, request.getOpenId(),
- request.getNickName(), request.getAvatarUrl(), "WECHAT_PHONE", null);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public EndUserDTO createAppleIdUser(AppleIdCreateRequest request) {
- if (request == null) {
- throw new ServiceException("参数不能为空");
- }
- return createUser(request.getAppleId(), null, request.getEmail(), null, null,
- request.getEmail(), request.getAvatar(), "APPLE_AUTH", request.getAppleId());
- }
- @Override
- public void resetPassword(AccountPasswordRequest request) {
- if (request == null || !StringUtils.hasText(request.getLoginId()) || !StringUtils.hasText(request.getNewPassword())) {
- throw new ServiceException("参数不能为空");
- }
- AppAccount account = poyeeAppAccountMapper.selectByLoginId(request.getLoginId());
- if (account == null) {
- throw new ServiceException("账号不存在");
- }
- String salt = randomSalt();
- String hash = hashPassword(request.getNewPassword(), salt);
- poyeeAppAccountMapper.updatePassword(account.getAccount(), hash, salt);
- }
- @Override
- public void changePassword(AccountPasswordRequest request) {
- if (request == null || !StringUtils.hasText(request.getOldPassword())) {
- throw new ServiceException("旧密码不能为空");
- }
- AppAccount account = poyeeAppAccountMapper.selectByLoginId(request.getLoginId());
- if (account == null) {
- throw new ServiceException("账号不存在");
- }
- String expected = hashPassword(request.getOldPassword(), resolvePasswordSalt(account));
- if (!expected.equalsIgnoreCase(account.getPassword())) {
- throw new ServiceException("旧密码错误");
- }
- resetPassword(request);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public EndUserDTO bindPhone(BindPhoneRequest request) {
- if (request == null || !StringUtils.hasText(request.getLoginId()) || !StringUtils.hasText(request.getPhone())) {
- throw new ServiceException("参数不能为空");
- }
- String loginId = request.getLoginId().trim();
- String phone = request.getPhone().trim();
- AppAccount account = poyeeAppAccountMapper.selectByLoginId(loginId);
- if (account == null) {
- throw new ServiceException("账号不存在");
- }
- AppAccount phoneAccount = poyeeAppAccountMapper.selectByLoginId(phone);
- if (phoneAccount != null && !isSameAccount(account, phoneAccount)) {
- throw new ServiceException("手机号已绑定");
- }
- poyeeAppAccountMapper.updatePhone(account.getAccount(), phone);
- account.setPhone(phone);
- AppBaseUser baseUser = poyeeAppBaseUserMapper.selectByUsername(account.getAccount());
- return toEndUser(account.getAccount(), account, baseUser);
- }
- @Override
- public AccountProfileInfoDTO getCurrentProfile(Integer userId) {
- if (userId == null) {
- throw new ServiceException("userId不能为空");
- }
- AppBaseUser baseUser = poyeeAppBaseUserMapper.selectById(userId);
- if (baseUser == null) {
- throw new ServiceException("用户不存在");
- }
- AppAccount account = StringUtils.hasText(baseUser.getUsername())
- ? poyeeAppAccountMapper.selectByLoginId(baseUser.getUsername())
- : null;
- AccountProfileInfoDTO profile = new AccountProfileInfoDTO();
- profile.setAvatar(baseUser.getAvatar());
- profile.setUserId(userId.longValue());
- profile.setLoginId(baseUser.getUsername());
- profile.setNickname(baseUser.getNickname());
- profile.setFaceVerify(baseUser.getFaceVerify());
- profile.setIdCard(baseUser.getIdCard());
- profile.setPhone(account == null ? null : account.getPhone());
- return profile;
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public AccountProfileInfoDTO mockRealNameVerify(Integer userId) {
- if (userId == null) {
- throw new ServiceException("userId cannot be null");
- }
- AppBaseUser baseUser = poyeeAppBaseUserMapper.selectById(userId);
- if (baseUser == null) {
- throw new ServiceException("user not found");
- }
- String idCard = randomIdCard();
- poyeeAppBaseUserMapper.updateRealNameVerify(userId, 1, idCard);
- AccountProfileInfoDTO profile = new AccountProfileInfoDTO();
- profile.setAvatar(baseUser.getAvatar());
- profile.setUserId(userId.longValue());
- profile.setNickname(baseUser.getNickname());
- profile.setFaceVerify(1);
- profile.setIdCard(idCard);
- return profile;
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public AccountProfileInfoDTO updateProfile(ProfileUpdateRequest request) {
- if (request == null || (request.getUserId() == null && !StringUtils.hasText(request.getLoginId()))) {
- throw new ServiceException("参数不能为空");
- }
- AppBaseUser baseUser = new AppBaseUser();
- baseUser.setId(request.getUserId());
- baseUser.setNickname(request.getNickname());
- baseUser.setAvatar(request.getAvatar());
- baseUser.setRealname(request.getRealname());
- baseUser.setBirthday(request.getBirthday());
- baseUser.setSex(request.getSex());
- if (baseUser.getId() == null && StringUtils.hasText(request.getLoginId())) {
- AppBaseUser existing = null;
- AppAccount account = poyeeAppAccountMapper.selectByLoginId(request.getLoginId());
- if (account != null) {
- existing = poyeeAppBaseUserMapper.selectByUsername(account.getAccount());
- }
- if (existing == null) {
- existing = poyeeAppBaseUserMapper.selectByExternalLoginId(request.getLoginId());
- }
- if (existing == null) {
- throw new ServiceException("用户不存在");
- }
- baseUser.setId(existing.getId());
- }
- poyeeAppBaseUserMapper.updateAppBaseUser(baseUser);
- return getCurrentProfile(baseUser.getId());
- }
- private boolean isSameAccount(AppAccount left, AppAccount right) {
- if (left.getId() != null && right.getId() != null) {
- return left.getId().equals(right.getId());
- }
- return left.getAccount() != null && left.getAccount().equals(right.getAccount());
- }
- private String resolvePhoneRegisterChannel(PhoneCreateRequest request) {
- String registerChannel = request.getRegisterChannel();
- if (!StringUtils.hasText(registerChannel)) {
- return UserType.THIRD_APK;
- }
- registerChannel = registerChannel.trim();
- if (UserType.THIRD_APK.equals(registerChannel) || UserType.THIRD_APP.equals(registerChannel)) {
- return registerChannel;
- }
- throw new ServiceException("手机号注册渠道不支持");
- }
- private EndUserDTO createUser(String username, String phone, String email, String password, String openId,
- String displayName, String avatar, String registerChannel, String transferSubId) {
- if (!StringUtils.hasText(username)) {
- throw new ServiceException("账号不能为空");
- }
- EndUserDTO existing = loadUserByLoginId(username);
- if (existing != null) {
- return existing;
- }
- AppAccount account = new AppAccount();
- account.setAccount(username);
- account.setPhone(phone);
- account.setEmail(email);
- account.setStatus((short) 0);
- account.setDelFlg((short) 0);
- account.setRoleid(DEFAULT_ROLE_ID);
- account.setCreateTime(new Date());
- if (StringUtils.hasText(password)) {
- String salt = randomSalt();
- account.setSalt(salt);
- account.setPassword(hashPassword(password, salt));
- }
- poyeeAppAccountMapper.insertAppAccount(account);
- AppBaseUser baseUser = new AppBaseUser();
- baseUser.setUsername(username);
- baseUser.setNickname(StringUtils.hasText(displayName) ? displayName : username);
- baseUser.setAvatar(StringUtils.hasText(avatar) ? avatar : DEFAULT_AVATAR);
- baseUser.setOpenid(openId);
- baseUser.setRegisterChannel(registerChannel);
- baseUser.setStatus((short) 0);
- baseUser.setDelFlg((short) 0);
- baseUser.setPoint(0L);
- baseUser.setLevel((short) 0);
- baseUser.setCreateTime(new Date());
- baseUser.setTransferSubId(transferSubId);
- poyeeAppBaseUserMapper.insertAppBaseUser(baseUser);
- return toEndUser(username, account, baseUser);
- }
- private EndUserDTO toEndUser(String loginId, AppAccount account, AppBaseUser baseUser) {
- if (account == null && baseUser == null) {
- return null;
- }
- EndUserDTO dto = new EndUserDTO();
- String username = account != null ? account.getAccount() : baseUser.getUsername();
- Integer userId = baseUser != null ? baseUser.getId() : account.getId();
- dto.setId(userId == null ? 0 : userId);
- dto.setUsername(username != null ? username : loginId);
- dto.setEmail(account == null ? null : account.getEmail());
- dto.setPhone(account == null ? null : account.getPhone());
- dto.setDisplayName(baseUser == null ? username : baseUser.getNickname());
- dto.setAvatarUrl(baseUser == null ? null : baseUser.getAvatar());
- dto.setPasswordHash(account == null ? null : account.getPassword());
- dto.setSalt(account == null ? null : account.getSalt());
- dto.setCode(baseUser == null ? null : baseUser.getCode());
- dto.setStatus(resolveStatus(account, baseUser));
- dto.setIdentityType(baseUser == null ? null : baseUser.getRegisterChannel());
- dto.setRegistrationTime(resolveRegistrationTime(account, baseUser));
- dto.setRoleCode(resolveRoleCodes(account));
- EndUserDTO.EndUserProfile profile = new EndUserDTO.EndUserProfile();
- profile.setRealName(baseUser == null ? null : baseUser.getRealname());
- profile.setGender(baseUser == null || baseUser.getSex() == null ? null : String.valueOf(baseUser.getSex()));
- profile.setBirthday(baseUser == null ? null : toLocalDate(baseUser.getBirthday()));
- profile.setIdCardNumber(baseUser == null ? null : baseUser.getIdCard());
- profile.setAddress(baseUser == null ? null : baseUser.getRegisterAddr());
- dto.setProfile(profile);
- return dto;
- }
- private LocalDateTime resolveRegistrationTime(AppAccount account, AppBaseUser baseUser) {
- Date createTime = baseUser != null && baseUser.getCreateTime() != null
- ? baseUser.getCreateTime()
- : account == null ? null : account.getCreateTime();
- return toLocalDateTime(createTime);
- }
- private LocalDateTime toLocalDateTime(Date date) {
- return date == null ? null : LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
- }
- private LocalDate toLocalDate(Date date) {
- return date == null ? null : date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
- }
- private List<String> resolveRoleCodes(AppAccount account) {
- if (account == null || account.getRoleid() == null) {
- return Collections.singletonList("PERSONAL");
- }
- List<String> roles = poyeeAppAccountMapper.selectRoleCodesByRoleId(account.getRoleid());
- return roles == null || roles.isEmpty() ? Collections.singletonList("PERSONAL") : roles;
- }
- private String resolveStatus(AppAccount account, AppBaseUser baseUser) {
- if (isDeleted(account, baseUser)) {
- return INACTIVE;
- }
- Short accountStatus = account == null ? null : account.getStatus();
- Short userStatus = baseUser == null ? null : baseUser.getStatus();
- if (Short.valueOf((short) 2).equals(accountStatus) || Short.valueOf((short) 2).equals(userStatus)) {
- return BANNED;
- }
- return ACTIVE;
- }
- private boolean isDeleted(AppAccount account, AppBaseUser baseUser) {
- return (account != null && Short.valueOf((short) 1).equals(account.getDelFlg()))
- || (baseUser != null && Short.valueOf((short) 1).equals(baseUser.getDelFlg()));
- }
- private String stableSalt(String username) {
- return md5("poyee-account:" + (username == null ? "" : username));
- }
- private String resolvePasswordSalt(AppAccount account) {
- return StringUtils.hasText(account.getSalt()) ? account.getSalt() : stableSalt(account.getAccount());
- }
- private String randomSalt() {
- byte[] bytes = new byte[16];
- SECURE_RANDOM.nextBytes(bytes);
- StringBuilder builder = new StringBuilder();
- for (byte b : bytes) {
- builder.append(String.format("%02x", b));
- }
- return builder.toString();
- }
- private String hashPassword(String password, String salt) {
- return md5(password + salt);
- }
- private String randomIdCard() {
- StringBuilder builder = new StringBuilder(18);
- for (int i = 0; i < 18; i++) {
- builder.append(SECURE_RANDOM.nextInt(10));
- }
- return builder.toString();
- }
- private String md5(String value) {
- try {
- MessageDigest digest = MessageDigest.getInstance("MD5");
- byte[] bytes = digest.digest(value.getBytes());
- StringBuilder builder = new StringBuilder();
- for (byte b : bytes) {
- builder.append(String.format("%02x", b));
- }
- return builder.toString();
- } catch (NoSuchAlgorithmException e) {
- throw new ServiceException("密码加密失败");
- }
- }
- }
|