浏览代码

系统用户接口

liu_lake 6 月之前
父节点
当前提交
0dce9a60ac

+ 9 - 1
db/db-agent/src/main/java/pay/platform/mapper/PayAgentMapper.java

@@ -1,8 +1,10 @@
 package pay.platform.mapper;
 
 import com.mybatisflex.core.BaseMapper;
+import com.mybatisflex.core.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 import pay.platform.domain.PayAgent;
+import pay.platform.domain.table.PayAgentTableDef;
 
 /**
  * 代理系统 映射层。
@@ -13,5 +15,11 @@ import pay.platform.domain.PayAgent;
 @Mapper
 public interface PayAgentMapper extends BaseMapper<PayAgent> {
 
-
+    default void resetPassword(String username, String newPassword) {
+        QueryWrapper queryWrapper = QueryWrapper.create().from(PayAgentTableDef.PAY_AGENT)
+                .where(PayAgentTableDef.PAY_AGENT.USER_NAME.eq(username));
+        PayAgent sysUser = selectOneByQuery(queryWrapper);
+        sysUser.setPassword(newPassword);
+        update(sysUser);
+    }
 }

+ 9 - 0
db/db-merchant/src/main/java/pay/platform/mapper/PayMerchantMapper.java

@@ -1,8 +1,10 @@
 package pay.platform.mapper;
 
 import com.mybatisflex.core.BaseMapper;
+import com.mybatisflex.core.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 import pay.platform.domain.PayMerchant;
+import pay.platform.domain.table.PayMerchantTableDef;
 
 /**
  * 商户管理 映射层。
@@ -13,5 +15,12 @@ import pay.platform.domain.PayMerchant;
 @Mapper
 public interface PayMerchantMapper extends BaseMapper<PayMerchant> {
 
+    default void resetPassword(String username, String newPassword) {
+        QueryWrapper queryWrapper = QueryWrapper.create().from(PayMerchantTableDef.PAY_MERCHANT)
+                .where(PayMerchantTableDef.PAY_MERCHANT.USER_NAME.eq(username));
+        PayMerchant sysUser = selectOneByQuery(queryWrapper);
+        sysUser.setPassword(newPassword);
+        update(sysUser);
+    }
 
 }

+ 2 - 1
web/admin-api/src/main/java/pay/platform/api/system/model/vo/PayAgentVO.java

@@ -7,6 +7,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
@@ -22,7 +23,7 @@ import java.time.LocalDateTime;
 @AllArgsConstructor
 @Schema(name = "代理系统")
 @Table(value = "t_pay_agent")
-public class PayAgentVO {
+public class PayAgentVO implements Serializable {
 
 
     /**

+ 2 - 1
web/admin-api/src/main/java/pay/platform/api/system/model/vo/PayAggregationVO.java

@@ -7,6 +7,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
@@ -22,7 +23,7 @@ import java.time.LocalDateTime;
 @AllArgsConstructor
 @Schema(name = "聚合支付")
 @Table(value = "t_pay_aggregation")
-public class PayAggregationVO {
+public class PayAggregationVO implements Serializable {
 
     /**
      * id

+ 2 - 1
web/admin-api/src/main/java/pay/platform/api/system/model/vo/PayChannelVO.java

@@ -7,6 +7,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
 import java.time.LocalDateTime;
 
 /**
@@ -21,7 +22,7 @@ import java.time.LocalDateTime;
 @AllArgsConstructor
 @Schema(name = "通道管理")
 @Table(value = "t_pay_channel")
-public class PayChannelVO {
+public class PayChannelVO implements Serializable {
 
     /**
      * id

+ 2 - 1
web/admin-api/src/main/java/pay/platform/api/system/model/vo/PayMerchantVO.java

@@ -7,6 +7,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
@@ -22,7 +23,7 @@ import java.time.LocalDateTime;
 @AllArgsConstructor
 @Schema(name = "商户管理")
 @Table(value = "t_pay_merchant")
-public class PayMerchantVO {
+public class PayMerchantVO implements Serializable {
 
     /**
      * id

+ 2 - 1
web/admin-api/src/main/java/pay/platform/api/system/model/vo/PayOrderVO.java

@@ -7,6 +7,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
@@ -22,7 +23,7 @@ import java.time.LocalDateTime;
 @AllArgsConstructor
 @Schema(name = "通道管理")
 @Table(value = "t_pay_order")
-public class PayOrderVO {
+public class PayOrderVO implements Serializable {
 
     /**
      * id

+ 2 - 1
web/admin-api/src/main/java/pay/platform/api/system/model/vo/PayPlatformSettingVO.java

@@ -7,6 +7,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
 import java.time.LocalDateTime;
 
 /**
@@ -21,7 +22,7 @@ import java.time.LocalDateTime;
 @AllArgsConstructor
 @Schema(name = "平台配置")
 @Table(value = "t_pay_platform_setting")
-public class PayPlatformSettingVO {
+public class PayPlatformSettingVO implements Serializable {
 
     /**
      * id

+ 98 - 0
web/agent-api/src/main/java/pay/platform/api/system/controller/PayAgentController.java

@@ -0,0 +1,98 @@
+package pay.platform.api.system.controller;
+
+import cn.bzvs.otp.OtpAuthUtil;
+import cn.hutool.core.util.StrUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import pay.platform.api.system.model.vo.PayAgentVO;
+import pay.platform.api.system.model.vo.RestPasswdVO;
+import pay.platform.api.system.servcie.PayAgentService;
+import pay.platform.core.common.Result;
+import pay.platform.core.security.model.UserInfo;
+import pay.platform.core.security.util.SecurityUtil;
+
+import java.time.LocalDateTime;
+
+/**
+ * 用户管理
+ */
+@RestController
+@RequestMapping("/sys/user")
+@Tag(name = "系统:用户管理")
+@RequiredArgsConstructor
+public class PayAgentController {
+
+    private final PayAgentService sysUserService;
+
+
+    @GetMapping("/check/username")
+    @Operation(summary = "检查用户名是否存在")
+    public Result<Boolean> checkUsername(HttpServletRequest request, @RequestParam String username) {
+        return sysUserService.hashUsername(username);
+    }
+
+
+    @PutMapping("/update/{id}")
+    @Operation(summary = "修改")
+    @PreAuthorize("@permission.hashPermission('user:update')")
+    public Result<PayAgentVO> update(HttpServletRequest request, @PathVariable String id,
+                                     @Validated @RequestBody PayAgentVO userVO) {
+
+        userVO.setUpdateTime(LocalDateTime.now());
+        userVO.setUpdateUser(SecurityUtil.getCurrentUsername());
+        return sysUserService.updateById(id, userVO);
+    }
+
+    @PutMapping("/reset/passwd/{username}")
+    @Operation(summary = "重置密码")
+    @PreAuthorize("@permission.hashPermission('user:reset:passwd')")
+    public Result<String> resetPasswd(HttpServletRequest request, @PathVariable(value = "username") String username,
+                                      @Validated @RequestBody RestPasswdVO vo) {
+        if (StrUtil.isBlank(vo.getNewPassword())) {
+            return Result.NG("新密码不能为空");
+        }
+        if (!vo.getNewPassword().equals(vo.getConfirmPassword())) {
+            return Result.NG("两次密码不一致");
+        }
+        return sysUserService.resetPassword(username, vo.getConfirmPassword());
+    }
+
+    @PutMapping("/change/passwd/{username}")
+    @Operation(summary = "修改密码")
+    public Result<String> changePasswd(HttpServletRequest request,
+                                       @PathVariable("username") String username, @Validated @RequestBody RestPasswdVO vo) {
+        if (StrUtil.isBlank(vo.getNewPassword())) {
+            return Result.NG("新密码不能为空");
+        }
+        if (!vo.getNewPassword().equals(vo.getConfirmPassword())) {
+            return Result.NG("两次密码不一致");
+        }
+        if (vo.getOldPassword().equals(vo.getNewPassword())) {
+            return Result.NG("新密码不能与旧密码相同");
+        }
+        return sysUserService.changePasswd(username, vo.getOldPassword(), vo.getNewPassword());
+    }
+
+    @GetMapping("/get/google/qrcode")
+    @Operation(summary = "获取谷歌二维码")
+    public Result<String> getGoogleQrcode() {
+        UserInfo userInfo = SecurityUtil.getCurrentUser();
+        String otp = sysUserService.createGoogleOtp(userInfo.getUserid());
+        OtpAuthUtil.getOtpAuthUrl("Game-System", otp);
+        return Result.OK(otp);
+    }
+
+
+    @PostMapping("/check/google/otp")
+    @Operation(summary = "校验谷歌验证码")
+    public Result<Boolean> googleOtpCheck(String code) {
+        UserInfo userInfo = SecurityUtil.getCurrentUser();
+        boolean status = sysUserService.checkGoogleOtp(userInfo.getUserid(), code);
+        return Result.OK(status);
+    }
+}

+ 69 - 0
web/agent-api/src/main/java/pay/platform/api/system/servcie/PayAgentService.java

@@ -2,6 +2,10 @@ package pay.platform.api.system.servcie;
 
 
 import com.mybatisflex.core.service.IService;
+import jakarta.annotation.Nonnull;
+import pay.platform.api.system.model.vo.PayAgentVO;
+import pay.platform.api.system.model.vo.UserVO;
+import pay.platform.core.common.Result;
 import pay.platform.domain.PayAgent;
 
 import java.util.Optional;
@@ -16,4 +20,69 @@ public interface PayAgentService extends IService<PayAgent> {
     Optional<PayAgent> loadUserByUsername(String username);
 
     boolean hasGoogleOtp(String userid);
+
+
+    /**
+     * 帐号是否存在
+     *
+     * @param username .
+     * @return .
+     */
+    public Result<Boolean> hashUsername(String username);
+
+    /**
+     * 根据ID获取详情
+     *
+     * @param id .
+     * @return .
+     */
+    public Result<UserVO> detail(String id);
+
+
+    /**
+     * 更新用户
+     *
+     * @param id .
+     * @param vo .
+     * @return .
+     */
+    public Result<PayAgentVO> updateById(String id, PayAgentVO vo);
+
+
+    /**
+     * 重置密码
+     *
+     * @param username .
+     * @param passwd   .
+     * @return .
+     */
+
+    public Result<String> resetPassword(@Nonnull String username, @Nonnull String passwd);
+
+    /**
+     * 修改密码
+     *
+     * @param username  .
+     * @param oldPasswd .
+     * @param newPasswd .
+     * @return .
+     */
+    public Result<String> changePasswd(@Nonnull String username, @Nonnull String oldPasswd, @Nonnull String newPasswd);
+
+    /**
+     * 创建谷歌验证器
+     *
+     * @param id ID
+     * @return otp
+     */
+    public String createGoogleOtp(String id);
+
+    /**
+     * 校验谷歌验证器
+     *
+     * @param id   ID
+     * @param code 验证码
+     * @return true/false
+     */
+    public boolean checkGoogleOtp(String id, String code);
 }

+ 122 - 0
web/agent-api/src/main/java/pay/platform/api/system/servcie/impl/PayAgentServiceImpl.java

@@ -1,11 +1,19 @@
 package pay.platform.api.system.servcie.impl;
 
 
+import cn.bzvs.otp.OtpAuthUtil;
+import cn.hutool.core.bean.BeanUtil;
 import com.mybatisflex.core.query.QueryWrapper;
+import jakarta.annotation.Nonnull;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
+import pay.platform.api.system.model.vo.PayAgentVO;
+import pay.platform.api.system.model.vo.UserVO;
 import pay.platform.api.system.servcie.PayAgentService;
+import pay.platform.core.common.Result;
 import pay.platform.core.common.domain.BaseService;
+import pay.platform.core.util.PasswordUtil;
 import pay.platform.domain.PayAgent;
 import pay.platform.domain.table.PayAgentTableDef;
 import pay.platform.mapper.PayAgentMapper;
@@ -19,6 +27,7 @@ import java.util.Optional;
  * @since 1.0
  */
 @Service
+@Slf4j
 public class PayAgentServiceImpl extends BaseService<PayAgentMapper, PayAgent> implements PayAgentService {
 
     /**
@@ -43,4 +52,117 @@ public class PayAgentServiceImpl extends BaseService<PayAgentMapper, PayAgent> i
         PayAgent sysUser = getById(id);
         return StringUtils.hasText(sysUser.getTpopCode());
     }
+
+
+    /**
+     * 帐号是否存在
+     *
+     * @param username .
+     * @return .
+     */
+    public Result<Boolean> hashUsername(String username) {
+        return Result.OK(loadUserByUsername(username).isPresent());
+    }
+
+    /**
+     * 根据ID获取详情
+     *
+     * @param id .
+     * @return .
+     */
+    public Result<UserVO> detail(String id) {
+        PayAgent user = getById(id);
+        UserVO res = BeanUtil.toBean(user, UserVO.class);
+        res.setPassword(null);
+        return Result.OK(res);
+    }
+
+
+    /**
+     * 更新用户
+     *
+     * @param id .
+     * @param vo .
+     * @return .
+     */
+    public Result<PayAgentVO> updateById(String id, PayAgentVO vo) {
+        PayAgent user = getById(id);
+        if (null == user) {
+            return Result.NG("用户不存在");
+        }
+        BeanUtil.copyProperties(vo, user);
+        updateById(user);
+        return Result.OK(vo);
+    }
+
+
+    /**
+     * 重置密码
+     *
+     * @param username .
+     * @param passwd   .
+     * @return .
+     */
+
+    public Result<String> resetPassword(@Nonnull String username, @Nonnull String passwd) {
+        String newPassword = PasswordUtil.encoder(passwd);
+        mapper.resetPassword(username, newPassword);
+        return Result.OK();
+    }
+
+    /**
+     * 修改密码
+     *
+     * @param username  .
+     * @param oldPasswd .
+     * @param newPasswd .
+     * @return .
+     */
+    public Result<String> changePasswd(@Nonnull String username, @Nonnull String oldPasswd, @Nonnull String newPasswd) {
+        Optional<PayAgent> sysUser = loadUserByUsername(username);
+        if (sysUser.isPresent()) {
+            return Result.NG("用户不存在");
+        }
+        PayAgent user = sysUser.get();
+        if (!PasswordUtil.matches(oldPasswd, user.getPassword())) {
+            return Result.NG("原密码错误");
+        }
+        String newPassword = PasswordUtil.encoder(newPasswd);
+        user.setPassword(newPassword);
+        mapper.update(user);
+        return Result.OK();
+    }
+
+
+    /**
+     * 创建谷歌验证器
+     *
+     * @param id ID
+     * @return otp
+     */
+    public String createGoogleOtp(String id) {
+        PayAgent sysUser = getById(id);
+        String secret = OtpAuthUtil.createSecret();
+        sysUser.setTpopCode(secret);
+        updateById(sysUser);
+        return OtpAuthUtil.getOtpQrCodeUrl("", secret);
+    }
+
+    /**
+     * 校验谷歌验证器
+     *
+     * @param id   ID
+     * @param code 验证码
+     * @return true/false
+     */
+    public boolean checkGoogleOtp(String id, String code) {
+        PayAgent sysUser = getById(id);
+        String secret = sysUser.getTpopCode();
+        if (Boolean.FALSE.equals(StringUtils.hasText(secret))) {
+            log.warn("用户未设置谷歌验证器");
+            return false;
+        }
+        return OtpAuthUtil.validateCode(secret, code);
+    }
+
 }

+ 98 - 0
web/merchant-api/src/main/java/pay/platform/api/system/controller/PayAgentController.java

@@ -0,0 +1,98 @@
+package pay.platform.api.system.controller;
+
+import cn.bzvs.otp.OtpAuthUtil;
+import cn.hutool.core.util.StrUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import pay.platform.api.system.model.vo.PayAgentVO;
+import pay.platform.api.system.model.vo.RestPasswdVO;
+import pay.platform.api.system.servcie.PayMerchantService;
+import pay.platform.core.common.Result;
+import pay.platform.core.security.model.UserInfo;
+import pay.platform.core.security.util.SecurityUtil;
+
+import java.time.LocalDateTime;
+
+/**
+ * 用户管理
+ */
+@RestController
+@RequestMapping("/sys/user")
+@Tag(name = "系统:用户管理")
+@RequiredArgsConstructor
+public class PayAgentController {
+
+    private final PayMerchantService sysUserService;
+
+
+    @GetMapping("/check/username")
+    @Operation(summary = "检查用户名是否存在")
+    public Result<Boolean> checkUsername(HttpServletRequest request, @RequestParam String username) {
+        return sysUserService.hashUsername(username);
+    }
+
+
+    @PutMapping("/update/{id}")
+    @Operation(summary = "修改")
+    @PreAuthorize("@permission.hashPermission('user:update')")
+    public Result<PayAgentVO> update(HttpServletRequest request, @PathVariable String id,
+                                     @Validated @RequestBody PayAgentVO userVO) {
+
+        userVO.setUpdateTime(LocalDateTime.now());
+        userVO.setUpdateUser(SecurityUtil.getCurrentUsername());
+        return sysUserService.updateById(id, userVO);
+    }
+
+    @PutMapping("/reset/passwd/{username}")
+    @Operation(summary = "重置密码")
+    @PreAuthorize("@permission.hashPermission('user:reset:passwd')")
+    public Result<String> resetPasswd(HttpServletRequest request, @PathVariable(value = "username") String username,
+                                      @Validated @RequestBody RestPasswdVO vo) {
+        if (StrUtil.isBlank(vo.getNewPassword())) {
+            return Result.NG("新密码不能为空");
+        }
+        if (!vo.getNewPassword().equals(vo.getConfirmPassword())) {
+            return Result.NG("两次密码不一致");
+        }
+        return sysUserService.resetPassword(username, vo.getConfirmPassword());
+    }
+
+    @PutMapping("/change/passwd/{username}")
+    @Operation(summary = "修改密码")
+    public Result<String> changePasswd(HttpServletRequest request,
+                                       @PathVariable("username") String username, @Validated @RequestBody RestPasswdVO vo) {
+        if (StrUtil.isBlank(vo.getNewPassword())) {
+            return Result.NG("新密码不能为空");
+        }
+        if (!vo.getNewPassword().equals(vo.getConfirmPassword())) {
+            return Result.NG("两次密码不一致");
+        }
+        if (vo.getOldPassword().equals(vo.getNewPassword())) {
+            return Result.NG("新密码不能与旧密码相同");
+        }
+        return sysUserService.changePasswd(username, vo.getOldPassword(), vo.getNewPassword());
+    }
+
+    @GetMapping("/get/google/qrcode")
+    @Operation(summary = "获取谷歌二维码")
+    public Result<String> getGoogleQrcode() {
+        UserInfo userInfo = SecurityUtil.getCurrentUser();
+        String otp = sysUserService.createGoogleOtp(userInfo.getUserid());
+        OtpAuthUtil.getOtpAuthUrl("Game-System", otp);
+        return Result.OK(otp);
+    }
+
+
+    @PostMapping("/check/google/otp")
+    @Operation(summary = "校验谷歌验证码")
+    public Result<Boolean> googleOtpCheck(String code) {
+        UserInfo userInfo = SecurityUtil.getCurrentUser();
+        boolean status = sysUserService.checkGoogleOtp(userInfo.getUserid(), code);
+        return Result.OK(status);
+    }
+}

+ 68 - 0
web/merchant-api/src/main/java/pay/platform/api/system/servcie/PayMerchantService.java

@@ -2,6 +2,10 @@ package pay.platform.api.system.servcie;
 
 
 import com.mybatisflex.core.service.IService;
+import jakarta.annotation.Nonnull;
+import pay.platform.api.system.model.vo.PayAgentVO;
+import pay.platform.api.system.model.vo.PayMerchantVO;
+import pay.platform.core.common.Result;
 import pay.platform.domain.PayMerchant;
 
 import java.util.Optional;
@@ -16,4 +20,68 @@ public interface PayMerchantService extends IService<PayMerchant> {
     Optional<PayMerchant> loadUserByUsername(String username);
 
     boolean hasGoogleOtp(String userid);
+
+    /**
+     * 帐号是否存在
+     *
+     * @param username .
+     * @return .
+     */
+    public Result<Boolean> hashUsername(String username);
+
+    /**
+     * 根据ID获取详情
+     *
+     * @param id .
+     * @return .
+     */
+    public Result<PayMerchantVO> detail(String id);
+
+
+    /**
+     * 更新用户
+     *
+     * @param id .
+     * @param vo .
+     * @return .
+     */
+    public Result<PayAgentVO> updateById(String id, PayAgentVO vo);
+
+
+    /**
+     * 重置密码
+     *
+     * @param username .
+     * @param passwd   .
+     * @return .
+     */
+
+    public Result<String> resetPassword(@Nonnull String username, @Nonnull String passwd);
+
+    /**
+     * 修改密码
+     *
+     * @param username  .
+     * @param oldPasswd .
+     * @param newPasswd .
+     * @return .
+     */
+    public Result<String> changePasswd(@Nonnull String username, @Nonnull String oldPasswd, @Nonnull String newPasswd);
+
+    /**
+     * 创建谷歌验证器
+     *
+     * @param id ID
+     * @return otp
+     */
+    public String createGoogleOtp(String id);
+
+    /**
+     * 校验谷歌验证器
+     *
+     * @param id   ID
+     * @param code 验证码
+     * @return true/false
+     */
+    public boolean checkGoogleOtp(String id, String code);
 }

+ 119 - 0
web/merchant-api/src/main/java/pay/platform/api/system/servcie/impl/PayMerchantServiceImpl.java

@@ -1,11 +1,19 @@
 package pay.platform.api.system.servcie.impl;
 
 
+import cn.bzvs.otp.OtpAuthUtil;
+import cn.hutool.core.bean.BeanUtil;
 import com.mybatisflex.core.query.QueryWrapper;
+import jakarta.annotation.Nonnull;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
+import pay.platform.api.system.model.vo.PayAgentVO;
+import pay.platform.api.system.model.vo.PayMerchantVO;
 import pay.platform.api.system.servcie.PayMerchantService;
+import pay.platform.core.common.Result;
 import pay.platform.core.common.domain.BaseService;
+import pay.platform.core.util.PasswordUtil;
 import pay.platform.domain.PayMerchant;
 import pay.platform.domain.table.PayAgentTableDef;
 import pay.platform.domain.table.PayMerchantTableDef;
@@ -20,6 +28,7 @@ import java.util.Optional;
  * @since 1.0
  */
 @Service
+@Slf4j
 public class PayMerchantServiceImpl extends BaseService<PayMerchantMapper, PayMerchant> implements PayMerchantService {
 
     /**
@@ -44,4 +53,114 @@ public class PayMerchantServiceImpl extends BaseService<PayMerchantMapper, PayMe
         PayMerchant sysUser = getById(id);
         return StringUtils.hasText(sysUser.getTpopCode());
     }
+
+    /**
+     * 帐号是否存在
+     *
+     * @param username .
+     * @return .
+     */
+    public Result<Boolean> hashUsername(String username) {
+        return Result.OK(loadUserByUsername(username).isPresent());
+    }
+
+    /**
+     * 根据ID获取详情
+     *
+     * @param id .
+     * @return .
+     */
+    public Result<PayMerchantVO> detail(String id) {
+        PayMerchant user = getById(id);
+        PayMerchantVO res = BeanUtil.toBean(user, PayMerchantVO.class);
+        return Result.OK(res);
+    }
+
+
+    /**
+     * 更新用户
+     *
+     * @param id .
+     * @param vo .
+     * @return .
+     */
+    public Result<PayAgentVO> updateById(String id, PayAgentVO vo) {
+        PayMerchant user = getById(id);
+        if (null == user) {
+            return Result.NG("用户不存在");
+        }
+        BeanUtil.copyProperties(vo, user);
+        updateById(user);
+        return Result.OK(vo);
+    }
+
+
+    /**
+     * 重置密码
+     *
+     * @param username .
+     * @param passwd   .
+     * @return .
+     */
+
+    public Result<String> resetPassword(@Nonnull String username, @Nonnull String passwd) {
+        String newPassword = PasswordUtil.encoder(passwd);
+        mapper.resetPassword(username, newPassword);
+        return Result.OK();
+    }
+
+    /**
+     * 修改密码
+     *
+     * @param username  .
+     * @param oldPasswd .
+     * @param newPasswd .
+     * @return .
+     */
+    public Result<String> changePasswd(@Nonnull String username, @Nonnull String oldPasswd, @Nonnull String newPasswd) {
+        Optional<PayMerchant> sysUser = loadUserByUsername(username);
+        if (sysUser.isPresent()) {
+            return Result.NG("用户不存在");
+        }
+        PayMerchant user = sysUser.get();
+        if (!PasswordUtil.matches(oldPasswd, user.getPassword())) {
+            return Result.NG("原密码错误");
+        }
+        String newPassword = PasswordUtil.encoder(newPasswd);
+        user.setPassword(newPassword);
+        mapper.update(user);
+        return Result.OK();
+    }
+
+
+    /**
+     * 创建谷歌验证器
+     *
+     * @param id ID
+     * @return otp
+     */
+    public String createGoogleOtp(String id) {
+        PayMerchant sysUser = getById(id);
+        String secret = OtpAuthUtil.createSecret();
+        sysUser.setTpopCode(secret);
+        updateById(sysUser);
+        return OtpAuthUtil.getOtpQrCodeUrl("", secret);
+    }
+
+    /**
+     * 校验谷歌验证器
+     *
+     * @param id   ID
+     * @param code 验证码
+     * @return true/false
+     */
+    public boolean checkGoogleOtp(String id, String code) {
+        PayMerchant sysUser = getById(id);
+        String secret = sysUser.getTpopCode();
+        if (Boolean.FALSE.equals(StringUtils.hasText(secret))) {
+            log.warn("用户未设置谷歌验证器");
+            return false;
+        }
+        return OtpAuthUtil.validateCode(secret, code);
+    }
 }