【7.0.4】【c】更新登录注册等接口

pull/22/head
fengshuonan 2021-06-07 19:02:34 +08:00
parent 2b715d90fe
commit 65710cc505
10 changed files with 461 additions and 10 deletions

View File

@ -16,6 +16,14 @@
<packaging>jar</packaging>
<dependencies>
<!--config模块的api-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>config-api</artifactId>
<version>${roses.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -41,7 +41,12 @@ public enum CustomerExceptionEnum implements AbstractExceptionEnum {
/**
*
*/
CANT_FIND_CUSTOMER(RuleConstants.BUSINESS_ERROR_TYPE_CODE + CustomerConstants.CUSTOMER_EXCEPTION_STEP_CODE + "01", "查询不到对应用户用户id是{}");
CANT_FIND_CUSTOMER(RuleConstants.BUSINESS_ERROR_TYPE_CODE + CustomerConstants.CUSTOMER_EXCEPTION_STEP_CODE + "01", "查询不到对应用户,用户信息:{}"),
/**
*
*/
CUSTOMER_STATUS_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + CustomerConstants.CUSTOMER_EXCEPTION_STEP_CODE + "02", "用户被禁用,请联系管理员!{}");
/**
*

View File

@ -0,0 +1,34 @@
package cn.stylefeng.roses.kernel.customer.api.expander;
import cn.stylefeng.roses.kernel.config.api.context.ConfigContext;
/**
* C
*
* @author fengshuonan
* @date 2021/6/7 15:38
*/
public class CustomerConfigExpander {
/**
*
*
* @author fengshuonan
* @date 2021/6/7 15:42
*/
public static String getRegMailTitle() {
return ConfigContext.me().getSysConfigValueWithDefault("CUSTOMER_REG_EMAIL_TITLE", String.class, "Guns官方论坛-激活");
}
/**
*
*
* @author fengshuonan
* @date 2021/6/7 15:42
*/
public static String getRegMailContent() {
return ConfigContext.me().getSysConfigValueWithDefault("CUSTOMER_REG_EMAIL_CONTENT", String.class, "感谢您注册Guns官方论坛请点击此激活链接激活您的账户<a href=\"http://localhost:8080/customer/active?verifyCode={}\">https://localhost:8080/customer/active?verifyCode={}</a>");
}
}

View File

@ -24,6 +24,22 @@
<version>${roses.version}</version>
</dependency>
<!--jwt api-->
<!--生成jwt秘钥-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>jwt-api</artifactId>
<version>${roses.version}</version>
</dependency>
<!--log api-->
<!--记录登录日志-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>log-api</artifactId>
<version>${roses.version}</version>
</dependency>
<!--资源api模块-->
<!--用在资源控制器,资源扫描上-->
<dependency>
@ -40,6 +56,14 @@
<version>${roses.version}</version>
</dependency>
<!--邮件发送模块-->
<!--用在控制器,参数校验-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>email-spring-boot-starter</artifactId>
<version>${roses.version}</version>
</dependency>
<!--数据库sdk-->
<!--数据库初始化-->
<dependency>

View File

@ -1,5 +1,7 @@
package cn.stylefeng.roses.kernel.customer.modular.controller;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse;
import cn.stylefeng.roses.kernel.customer.modular.request.CustomerRequest;
import cn.stylefeng.roses.kernel.customer.modular.service.CustomerService;
import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData;
@ -26,6 +28,42 @@ public class CustomerController {
@Resource
private CustomerService customerService;
/**
* C
*
* @author fengshuonan
* @date 2021/06/07 11:40
*/
@PostResource(name = "注册C端用户", path = "/customer/reg", requiredPermission = false, requiredLogin = false)
public ResponseData reg(@RequestBody @Validated(CustomerRequest.reg.class) CustomerRequest customerRequest) {
customerService.reg(customerRequest);
return new SuccessResponseData();
}
/**
* C
*
* @author fengshuonan
* @date 2021/6/7 16:03
*/
@GetResource(name = "激活C端用户", path = "/customer/active", requiredPermission = false, requiredLogin = false)
public ResponseData active(@Validated(CustomerRequest.active.class) CustomerRequest customerRequest) {
customerService.active(customerRequest);
return new SuccessResponseData();
}
/**
* C
*
* @author fengshuonan
* @date 2021/06/07 11:40
*/
@PostResource(name = "C端用户登录", path = "/customer/login", requiredPermission = false, requiredLogin = false)
public ResponseData login(@RequestBody @Validated LoginRequest loginRequest) {
LoginResponse loginResponse = customerService.login(loginRequest);
return new SuccessResponseData(loginResponse);
}
/**
*
*

View File

@ -9,6 +9,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
/**
* C
*
@ -35,7 +37,7 @@ public class Customer extends BaseEntity {
private String account;
/**
*
* BCrypt
*/
@TableField("password")
@ChineseDescription("密码")
@ -45,7 +47,7 @@ public class Customer extends BaseEntity {
*
*/
@TableField("nick_name")
@ChineseDescription("昵称(显示名称)")
@ChineseDescription("昵称")
private String nickName;
/**
@ -62,11 +64,25 @@ public class Customer extends BaseEntity {
@ChineseDescription("手机")
private String telephone;
/**
*
*/
@TableField("verify_code")
@ChineseDescription("邮箱或手机验证码")
private String verifyCode;
/**
* Y-N-
*/
@TableField("verified_flag")
@ChineseDescription("是否已经邮箱或手机验证通过")
private String verifiedFlag;
/**
* id
*/
@TableField("avatar")
@ChineseDescription("用户头像文件表id")
@ChineseDescription("用户头像")
private Long avatar;
/**
@ -83,4 +99,25 @@ public class Customer extends BaseEntity {
@ChineseDescription("用户积分")
private Integer score;
/**
* 1-2-
*/
@TableField("status_flag")
@ChineseDescription("用户状态1-启用2-禁用")
private Integer statusFlag;
/**
* ip
*/
@TableField("last_login_ip")
@ChineseDescription("上次登录ip")
private String lastLoginIp;
/**
*
*/
@TableField("last_login_time")
@ChineseDescription("上次登录时间")
private Date lastLoginTime;
}

View File

@ -0,0 +1,107 @@
package cn.stylefeng.roses.kernel.customer.modular.factory;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.basic.SimpleUserInfo;
import cn.stylefeng.roses.kernel.customer.api.expander.CustomerConfigExpander;
import cn.stylefeng.roses.kernel.customer.modular.entity.Customer;
import cn.stylefeng.roses.kernel.customer.modular.request.CustomerRequest;
import cn.stylefeng.roses.kernel.email.api.pojo.SendMailParam;
import cn.stylefeng.roses.kernel.rule.enums.StatusEnum;
import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum;
import java.util.Date;
/**
* C
*
* @author fengshuonan
* @date 2021/6/7 15:10
*/
public class CustomerFactory {
/**
*
*
* @author fengshuonan
* @date 2021/6/7 15:10
*/
public static Customer createRegCustomer(CustomerRequest customerRequest) {
Customer customer = new Customer();
// 账号
customer.setAccount(customerRequest.getAccount());
// 密码
PasswordStoredEncryptApi passwordStoredEncryptApi = SpringUtil.getBean(PasswordStoredEncryptApi.class);
customer.setPassword(passwordStoredEncryptApi.encrypt(customerRequest.getPassword()));
// 昵称
customer.setNickName(customerRequest.getNickName());
// 邮箱
customer.setEmail(customerRequest.getEmail());
// 生成随机邮箱验证码
customer.setVerifyCode(RandomUtil.randomString(29).toUpperCase());
// 设置是否已经验证,未验证
customer.setVerifiedFlag(YesOrNotEnum.N.getCode());
// 设置默认头像
customer.setAvatar(10000L);
customer.setAvatarObjectName("10000.png");
// 设置默认积分0
customer.setScore(0);
// 设置状态
customer.setStatusFlag(StatusEnum.ENABLE.getCode());
return customer;
}
/**
*
*
* @author fengshuonan
* @date 2021/6/7 15:27
*/
public static SendMailParam createRegEmailParam(String mail, String verifyCode) {
String title = CustomerConfigExpander.getRegMailTitle();
String template = CustomerConfigExpander.getRegMailContent();
SendMailParam sendMailParam = new SendMailParam();
sendMailParam.setTo(mail);
sendMailParam.setTitle(title);
sendMailParam.setContent(StrUtil.format(template, verifyCode, verifyCode));
return sendMailParam;
}
/**
* loginUser
*
* @author fengshuonan
* @date 2021/6/7 17:06
*/
public static LoginUser createLoginUser(Customer customer) {
LoginUser loginUser = new LoginUser();
loginUser.setUserId(customer.getCustomerId());
loginUser.setAccount(customer.getAccount());
loginUser.setLoginTime(new Date());
SimpleUserInfo simpleUserInfo = new SimpleUserInfo();
simpleUserInfo.setAvatar(customer.getAvatar());
simpleUserInfo.setNickName(customer.getNickName());
simpleUserInfo.setEmail(customer.getEmail());
simpleUserInfo.setPhone(customer.getTelephone());
loginUser.setSimpleUserInfo(simpleUserInfo);
return loginUser;
}
}

View File

@ -2,6 +2,7 @@ package cn.stylefeng.roses.kernel.customer.modular.request;
import cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest;
import cn.stylefeng.roses.kernel.scanner.api.annotation.field.ChineseDescription;
import cn.stylefeng.roses.kernel.validator.api.validators.unique.TableUniqueValue;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -28,28 +29,43 @@ public class CustomerRequest extends BaseRequest {
/**
*
*/
@NotBlank(message = "账号不能为空", groups = {add.class, edit.class})
@ChineseDescription("账号")
@NotBlank(message = "账号不能为空", groups = {add.class, edit.class, reg.class})
@TableUniqueValue(
message = "账号存在重复,请从新输入账号",
groups = reg.class,
tableName = "toc_customer",
columnName = "account",
idFieldName = "customer_id")
private String account;
/**
*
* BCrypt
*/
@NotBlank(message = "密码不能为空", groups = {add.class, edit.class})
@ChineseDescription("密码")
@NotBlank(message = "密码BCrypt不能为空", groups = {add.class, edit.class, reg.class})
private String password;
/**
*
*/
@NotBlank(message = "昵称(显示名称)不能为空", groups = {add.class, edit.class})
@ChineseDescription("昵称(显示名称)")
@ChineseDescription("昵称")
@NotBlank(message = "昵称(显示名称)不能为空", groups = {add.class, edit.class, reg.class})
private String nickName;
/**
*
* <p>
*
*/
@ChineseDescription("邮箱")
@NotBlank(message = "邮箱不能为空", groups = {reg.class})
@TableUniqueValue(
message = "邮箱存在重复,请从新输入邮箱",
groups = reg.class,
tableName = "toc_customer",
columnName = "email",
idFieldName = "customer_id")
private String email;
/**
@ -58,10 +74,23 @@ public class CustomerRequest extends BaseRequest {
@ChineseDescription("手机")
private String telephone;
/**
*
*/
@ChineseDescription("邮箱或手机验证码")
@NotBlank(message = "激活码不能为空", groups = active.class)
private String verifyCode;
/**
* Y-N-
*/
@ChineseDescription("是否已经邮箱或手机验证通过")
private String verifiedFlag;
/**
* id
*/
@ChineseDescription("用户头像文件表id")
@ChineseDescription("用户头像")
private Long avatar;
/**
@ -76,4 +105,22 @@ public class CustomerRequest extends BaseRequest {
@ChineseDescription("用户积分")
private Integer score;
/**
* 1-2-
*/
@ChineseDescription("用户状态1-启用2-禁用")
private Integer statusFlag;
/**
*
*/
public @interface reg {
}
/**
*
*/
public @interface active {
}
}

View File

@ -1,5 +1,7 @@
package cn.stylefeng.roses.kernel.customer.modular.service;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse;
import cn.stylefeng.roses.kernel.customer.modular.entity.Customer;
import cn.stylefeng.roses.kernel.customer.modular.request.CustomerRequest;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
@ -15,6 +17,30 @@ import java.util.List;
*/
public interface CustomerService extends IService<Customer> {
/**
*
*
* @author fengshuonan
* @date 2021/06/07 11:40
*/
void reg(CustomerRequest customerRequest);
/**
*
*
* @author fengshuonan
* @date 2021/06/07 11:40
*/
void active(CustomerRequest customerRequest);
/**
* C
*
* @author fengshuonan
* @date 2021/6/7 16:20
*/
LoginResponse login(LoginRequest loginRequest);
/**
*
*

View File

@ -2,20 +2,43 @@ package cn.stylefeng.roses.kernel.customer.modular.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
import cn.stylefeng.roses.kernel.auth.api.exception.AuthException;
import cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum;
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.customer.api.exception.CustomerException;
import cn.stylefeng.roses.kernel.customer.api.exception.enums.CustomerExceptionEnum;
import cn.stylefeng.roses.kernel.customer.modular.entity.Customer;
import cn.stylefeng.roses.kernel.customer.modular.factory.CustomerFactory;
import cn.stylefeng.roses.kernel.customer.modular.mapper.CustomerMapper;
import cn.stylefeng.roses.kernel.customer.modular.request.CustomerRequest;
import cn.stylefeng.roses.kernel.customer.modular.service.CustomerService;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.email.api.MailSenderApi;
import cn.stylefeng.roses.kernel.email.api.pojo.SendMailParam;
import cn.stylefeng.roses.kernel.jwt.api.context.JwtContext;
import cn.stylefeng.roses.kernel.jwt.api.pojo.payload.DefaultJwtPayload;
import cn.stylefeng.roses.kernel.log.api.LoginLogServiceApi;
import cn.stylefeng.roses.kernel.rule.enums.StatusEnum;
import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.rule.exception.enums.defaults.DefaultBusinessExceptionEnum;
import cn.stylefeng.roses.kernel.rule.util.HttpServletUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
@ -27,6 +50,108 @@ import java.util.List;
@Service
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements CustomerService {
/**
*
*/
private static final Object SESSION_OPERATE_LOCK = new Object();
@Resource
private MailSenderApi mailSenderApi;
@Resource
private PasswordStoredEncryptApi passwordStoredEncryptApi;
@Resource
private SessionManagerApi sessionManagerApi;
@Resource
private LoginLogServiceApi loginLogServiceApi;
@Override
@Transactional(rollbackFor = Exception.class)
public void reg(CustomerRequest customerRequest) {
// 创建C端用户
Customer regCustomer = CustomerFactory.createRegCustomer(customerRequest);
// 保存用户
this.save(regCustomer);
// 发送邮箱验证码
SendMailParam regEmailParam = CustomerFactory.createRegEmailParam(regCustomer.getEmail(), regCustomer.getVerifyCode());
mailSenderApi.sendMail(regEmailParam);
}
@Override
public void active(CustomerRequest customerRequest) {
// 更新验证码的账号为激活状态
LambdaUpdateWrapper<Customer> wrapper = new LambdaUpdateWrapper<>();
wrapper.set(Customer::getVerifiedFlag, YesOrNotEnum.Y.getCode());
wrapper.eq(Customer::getVerifyCode, customerRequest.getVerifyCode());
this.update(wrapper);
}
@Override
public LoginResponse login(LoginRequest loginRequest) {
// 不创建cookie默认开启记住我7天会话
loginRequest.setCreateCookie(false);
loginRequest.setRememberMe(true);
// 查询用户信息
LambdaQueryWrapper<Customer> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Customer::getAccount, loginRequest.getAccount())
.or().eq(Customer::getEmail, loginRequest.getAccount())
.or().eq(Customer::getTelephone, loginRequest.getAccount());
Customer customer = this.getOne(wrapper, false);
if (customer == null) {
throw new CustomerException(CustomerExceptionEnum.CANT_FIND_CUSTOMER, loginRequest.getAccount());
}
// 校验用户密码
Boolean passwordFlag = passwordStoredEncryptApi.checkPassword(loginRequest.getPassword(), customer.getPassword());
if (!passwordFlag) {
throw new AuthException(AuthExceptionEnum.USERNAME_PASSWORD_ERROR);
}
// 校验用户状态
if (!StatusEnum.ENABLE.getCode().equals(customer.getStatusFlag())) {
throw new CustomerException(CustomerExceptionEnum.CUSTOMER_STATUS_ERROR, customer.getStatusFlag());
}
// 获取LoginUser用于用户的缓存
LoginUser loginUser = CustomerFactory.createLoginUser(customer);
// 生成用户的token
DefaultJwtPayload defaultJwtPayload = new DefaultJwtPayload(loginUser.getUserId(), loginUser.getAccount(), loginRequest.getRememberMe(), null);
String jwtToken = JwtContext.me().generateTokenDefaultPayload(defaultJwtPayload);
loginUser.setToken(jwtToken);
synchronized (SESSION_OPERATE_LOCK) {
// 缓存用户信息,创建会话
sessionManagerApi.createSession(jwtToken, loginUser, loginRequest.getCreateCookie());
// 如果开启了单账号单端在线,则踢掉已经上线的该用户
if (AuthConfigExpander.getSingleAccountLoginFlag()) {
sessionManagerApi.removeSessionExcludeToken(jwtToken);
}
}
// 更新用户ip和登录时间
String ip = HttpServletUtil.getRequestClientIp(HttpServletUtil.getRequest());
LambdaUpdateWrapper<Customer> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(Customer::getLastLoginIp, ip);
updateWrapper.set(Customer::getLastLoginTime, new Date());
this.update(updateWrapper);
// 登录成功日志
loginLogServiceApi.loginSuccess(loginUser.getUserId());
// 组装返回结果
return new LoginResponse(loginUser, jwtToken, defaultJwtPayload.getExpirationDate());
}
@Override
public void add(CustomerRequest customerRequest) {
Customer customer = new Customer();