|
|
@@ -0,0 +1,434 @@
|
|
|
+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.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 EndUserDTO 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);
|
|
|
+ AppBaseUser updated = poyeeAppBaseUserMapper.selectById(baseUser.getId());
|
|
|
+ AppAccount account = updated == null ? null : poyeeAppAccountMapper.selectByLoginId(updated.getUsername());
|
|
|
+ return toEndUser(updated == null ? request.getLoginId() : updated.getUsername(), account, updated);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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("密码加密失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|