Commit 0d81a6b5 by 段启岩

邮箱,手机号绑定完成

parent 3be4b2ff
......@@ -132,13 +132,13 @@ POST /api/user/register/email
POST /api/user/active/{activeCode}
```
###### 23.绑定手机号
###### :white_check_mark: 23.绑定手机号
```
POST /api/user/binding/mobile
```
###### 24.绑定邮箱
###### :white_check_mark: 24.绑定邮箱
```
POST /api/user/binding/email
......@@ -657,3 +657,13 @@ GET /api/content/{contentId}
```
GET /api/channel/{channelId}/contents
```
### 十二、邮箱
###### :white_check_mark: 1.发送验证码
```
GET /api/mail/verifyCode
```
......@@ -6,7 +6,9 @@ package cn.meteor.beyondclouds.core.redis;
*/
public final class RedisKey {
private static final String KEY_PREFIX_MOBILE_VERIFY_CODE = "vcode:";
private static final String KEY_PREFIX_MOBILE_VERIFY_CODE = "verify_code_mobile:";
private static final String KEY_PREFIX_EMAIL_VERIFY_CODE = "verify_code_email:";
private static final String KEY_PREFIX_EMAIL_ACTIVE_CODE = "email_active_code:";
......@@ -19,6 +21,20 @@ public final class RedisKey {
return KEY_PREFIX_MOBILE_VERIFY_CODE + mobile;
}
/**
* 邮箱验证码
* @param email
* @return
*/
public static String EMAIL_VERIFY_CODE(String email) {
return KEY_PREFIX_MOBILE_VERIFY_CODE + email;
}
/**
* 邮箱激活码
* @param activeCode
* @return
*/
public static String EMAIL_ACTIVE_CODE(String activeCode) {
return KEY_PREFIX_EMAIL_ACTIVE_CODE + activeCode;
}
......
package cn.meteor.beyondclouds.modules.mail.api;
import cn.meteor.beyondclouds.common.enums.ErrorCode;
import cn.meteor.beyondclouds.core.annotation.Anonymous;
import cn.meteor.beyondclouds.core.api.Response;
import cn.meteor.beyondclouds.modules.mail.service.IMailService;
import cn.meteor.beyondclouds.util.VerifyCodeUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author meteor
*/
@RestController
@RequestMapping("/api/mail")
@Api(tags = "邮箱API")
public class MailApi {
private IMailService mailService;
@Autowired
public void setMailService(IMailService mailService) {
this.mailService = mailService;
}
@Anonymous
@ApiOperation("发送验证码")
@GetMapping("/verifyCode")
public Response sendVerify(@RequestParam("email") String email) {
try {
mailService.sendVerifyCode(email, VerifyCodeUtils.randomVerifyCode());
return Response.success();
} catch (Exception e) {
e.printStackTrace();
return Response.error(ErrorCode.OPERATION_FAILED);
}
}
}
......@@ -20,4 +20,10 @@ public interface IMailService {
*/
void sendHtmlMail(EmailDTO email);
/**
* 发送验证码
* @param email
* @param randomVerifyCode
*/
void sendVerifyCode(String email, String randomVerifyCode);
}
package cn.meteor.beyondclouds.modules.mail.service.impl;
import cn.meteor.beyondclouds.common.helper.IRedisHelper;
import cn.meteor.beyondclouds.core.redis.RedisKey;
import cn.meteor.beyondclouds.modules.mail.dto.EmailDTO;
import cn.meteor.beyondclouds.modules.mail.service.IMailService;
import cn.meteor.beyondclouds.modules.mail.util.EmailUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
......@@ -19,10 +22,12 @@ import javax.mail.internet.MimeMessage;
public class MailServiceImpl implements IMailService {
private JavaMailSender mailSender;
private IRedisHelper redisHelper;
@Autowired
public MailServiceImpl(JavaMailSender mailSender) {
public MailServiceImpl(JavaMailSender mailSender, IRedisHelper redisHelper) {
this.mailSender = mailSender;
this.redisHelper = redisHelper;
}
@Override
......@@ -56,4 +61,15 @@ public class MailServiceImpl implements IMailService {
log.error("发送邮件异常!", e.getMessage());
}
}
@Override
public void sendVerifyCode(String email, String randomVerifyCode) {
//1. 发送验证码
EmailDTO emailDTO =
new EmailDTO("13546386889@163.com", email,
"云里云外开源社区-验证码", EmailUtils.generateVerifyCodeMail(randomVerifyCode));
sendHtmlMail(emailDTO);
//2.存储验证码到redis
redisHelper.set(RedisKey.EMAIL_VERIFY_CODE(email), randomVerifyCode, 5 * 60);
}
}
package cn.meteor.beyondclouds.modules.user.util;
package cn.meteor.beyondclouds.modules.mail.util;
/**
* @author meteor
*/
public class ActivceCodeEmailUtils {
public class EmailUtils {
/**
* 生成激活邮件
* @param activeUrl
* @return
*/
public static String generateMail(String activeUrl) {
public static String generateActiveMail(String activeUrl) {
StringBuilder builder = new StringBuilder();
builder.append("<html>");
builder.append("<head>");
......@@ -31,7 +31,26 @@ public class ActivceCodeEmailUtils {
return builder.toString();
}
public static void main(String[] args) {
System.out.println(generateMail("http://a.com/aaa"));
/**
* 生成验证码邮件
* @param verifyCode
* @return
*/
public static String generateVerifyCodeMail(String verifyCode) {
StringBuilder builder = new StringBuilder();
builder.append("<html>");
builder.append("<head>");
builder.append("<title>");
builder.append("云里云外开源社区激活邮件");
builder.append("</title>");
builder.append("<meta charset=\"UTF-8\">");
builder.append("</head>");
builder.append("<body>");
builder.append("云里云外开源社区,您的验证码为<strong>");
builder.append(verifyCode);
builder.append("</strong>");
builder.append("</body>");
builder.append("</html>");
return builder.toString();
}
}
......@@ -10,9 +10,7 @@ import cn.meteor.beyondclouds.modules.user.entity.User;
import cn.meteor.beyondclouds.modules.user.entity.UserBlacklist;
import cn.meteor.beyondclouds.modules.user.entity.UserFollow;
import cn.meteor.beyondclouds.modules.user.exception.UserServiceException;
import cn.meteor.beyondclouds.modules.user.form.EmailRegisterFrom;
import cn.meteor.beyondclouds.modules.user.form.UserBaseInfoFrom;
import cn.meteor.beyondclouds.modules.user.form.MobileRegisterFrom;
import cn.meteor.beyondclouds.modules.user.form.*;
import cn.meteor.beyondclouds.modules.user.service.IUserBlacklistService;
import cn.meteor.beyondclouds.modules.user.service.IUserFollowService;
import cn.meteor.beyondclouds.modules.user.service.IUserService;
......@@ -85,6 +83,39 @@ public class UserApi {
}
}
@ApiOperation("绑定邮箱")
@PostMapping("/user/binding/email")
public Response bindEmail(@Valid EmailBindingFrom emailBindingFrom, BindingResult result, @CurrentSubject Subject subject) {
if (result.hasErrors()) {
return Response.fieldError(result.getFieldError());
}
try {
userService.bindEMail(emailBindingFrom.getEmail(), emailBindingFrom.getVerifyCode(), (String) subject.getId());
return Response.success();
} catch (UserServiceException e) {
e.printStackTrace();
return Response.error(e);
}
}
@ApiOperation("绑定手机号")
@PostMapping("/user/binding/mobile")
public Response bindMobile(@Valid MobileBindingFrom mobileBindingFrom, BindingResult result, @CurrentSubject Subject subject) {
if (result.hasErrors()) {
return Response.fieldError(result.getFieldError());
}
try {
userService.bindMobile(mobileBindingFrom.getMobile(), mobileBindingFrom.getVerifyCode(), (String) subject.getId());
return Response.success();
} catch (UserServiceException e) {
e.printStackTrace();
return Response.error(e);
}
}
@Anonymous
@ApiOperation("激活账号")
@GetMapping("/user/active/{activeCode}")
......
......@@ -11,8 +11,8 @@ public enum UserErrorCode implements IErrorCode {
/**
* 手机号已经被注册//
*/
MOBILE_REGISTERED(1001, "该手机号已被注册"),
EMAIL_REGISTERED(1002, "该邮箱已被注册"),
MOBILE_REGISTERED(1001, "该手机号已被占用"),
EMAIL_REGISTERED(1002, "该邮箱已被占用"),
REG_VERIFY_CODE_ERROR(1003, "验证码错误"),
CAN_NOT_FOLLOW_SELF(1004, "不能关注自己"),
FOLLOWED_USER_NOT_EXISTS(1005, "被关注用户不存在"),
......@@ -23,7 +23,10 @@ public enum UserErrorCode implements IErrorCode {
YOU_ALREADY_BLACKED(10010,"你已经被对方拉进黑名单"),
CAN_NOT_BLACK_SELF(10011,"不能拉黑自己"),
USER_NOT_BLACKED(10012,"用户没有被拉黑"),
INVALID_ACTIVE_CODE(10013, "非法的激活码");
INVALID_ACTIVE_CODE(10013, "非法的激活码"),
BINDING_EMAIL_VERIFY_CODE_ERROR(10014, "邮箱验证码错误"),
BINDING_MOBILE_VERIFY_CODE_ERROR(10015, "手机验证码错误"),
NON_LOCAL_AUTH_INFO(10016, "该手机未注册");
UserErrorCode(long code, String msg) {
this.code = code;
......
package cn.meteor.beyondclouds.modules.user.form;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* @author meteor
*/
@Data
public class EmailBindingFrom {
@Email(message = "邮箱格式不准确")
@NotNull(message = "邮箱不能为空")
private String email;
@NotEmpty(message = "验证码")
private String verifyCode;
}
package cn.meteor.beyondclouds.modules.user.form;
import cn.meteor.beyondclouds.core.constant.RegexPatterns;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
/**
* @author meteor
*/
@Data
public class MobileBindingFrom {
@NotEmpty(message = "手机不能为空")
@NotNull(message = "手机号不能为空")
@Pattern(regexp = RegexPatterns.MOBILE, message = "手机号格式不正确")
private String mobile;
@NotEmpty(message = "验证码不能为空")
private String verifyCode;
}
......@@ -61,4 +61,20 @@ public interface IUserService extends IService<User> {
* @param activeCode
*/
void activeAccount(String activeCode) throws UserServiceException;
/**
* 绑定邮箱
* @param email
* @param verifyCode
* @param userId
*/
void bindEMail(String email, String verifyCode, String userId) throws UserServiceException;
/**
* 绑定手机号
* @param mobile
* @param verifyCode
* @param userId
*/
void bindMobile(String mobile, String verifyCode, String userId) throws UserServiceException;
}
......@@ -17,7 +17,7 @@ import cn.meteor.beyondclouds.modules.user.mapper.IUserMapper;
import cn.meteor.beyondclouds.modules.user.service.IUserAuthAppService;
import cn.meteor.beyondclouds.modules.user.service.IUserAuthLocalService;
import cn.meteor.beyondclouds.modules.user.service.IUserService;
import cn.meteor.beyondclouds.modules.user.util.ActivceCodeEmailUtils;
import cn.meteor.beyondclouds.modules.mail.util.EmailUtils;
import cn.meteor.beyondclouds.util.Md5Utils;
import cn.meteor.beyondclouds.util.UUIDUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
......@@ -27,8 +27,11 @@ 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;
import org.springframework.util.StringUtils;
import java.util.List;
/**
* @author meteor
*/
......@@ -138,7 +141,7 @@ public class UserServiceImpl extends ServiceImpl<IUserMapper, User> implements I
String activeUrl = "http://opensource.yundingshuyuan.com/api/user/active/" + activeCode;
EmailDTO emailDTO = new EmailDTO("13546386889@163.com",
email, "云里云外激活邮件",
ActivceCodeEmailUtils.generateMail(activeUrl));
EmailUtils.generateActiveMail(activeUrl));
mailService.sendHtmlMail(emailDTO);
}
......@@ -179,18 +182,25 @@ public class UserServiceImpl extends ServiceImpl<IUserMapper, User> implements I
@Override
public void alterPassword(String mobile, String password, String verifyCode) throws UserServiceException {
//1.检查验证码是否正确
// 1.检查验证码是否正确
String realVerifyCode = redisHelper.get(RedisKey.MOBILE_VERIFY_CODE(mobile));
if (StringUtils.isEmpty(realVerifyCode) || !realVerifyCode.equals(verifyCode)) {
throw new UserServiceException(UserErrorCode.REG_VERIFY_CODE_ERROR);
}
// 删除验证码
// 2.删除验证码
redisHelper.del(RedisKey.MOBILE_VERIFY_CODE(mobile));
// 3.判断手机号是否注册
UserAuthLocal userAuthLocal = userAuthLocalService.getByAccount(mobile);
if (null == userAuthLocal) {
throw new UserServiceException(UserErrorCode.NON_LOCAL_AUTH_INFO);
}
// 4.更新所有本地认证信息里面的密码
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.set("password", Md5Utils.encode(password));
updateWrapper.eq("account", mobile);
updateWrapper.eq("user_id", userAuthLocal.getUserId());
userAuthLocalService.update(updateWrapper);
}
......@@ -221,4 +231,82 @@ public class UserServiceImpl extends ServiceImpl<IUserMapper, User> implements I
// 3.删除激活码
redisHelper.del(RedisKey.EMAIL_ACTIVE_CODE(activeCode));
}
@Transactional(rollbackFor = Exception.class)
@Override
public void bindEMail(String email, String verifyCode, String userId) throws UserServiceException {
// 1.检测验证码
String realVerifyCode = redisHelper.get(RedisKey.EMAIL_VERIFY_CODE(email));
if (StringUtils.isEmpty(realVerifyCode) || !realVerifyCode.equals(verifyCode)) {
throw new UserServiceException(UserErrorCode.BINDING_EMAIL_VERIFY_CODE_ERROR);
}
// 2.删除验证码
redisHelper.del(RedisKey.EMAIL_VERIFY_CODE(email));
// 3.检测该邮箱是否已被占用
UserAuthLocal userAuthLocal = userAuthLocalService.getByAccount(email);
if (null != userAuthLocal) {
throw new UserServiceException(UserErrorCode.EMAIL_REGISTERED);
}
// 4.从其他本地认证里面查找用户密码
String password = getPasswordInUserAuthLocal(userId);
// 5.绑定邮箱
userAuthLocal = new UserAuthLocal();
userAuthLocal.setUserId(userId);
userAuthLocal.setAccount(email);
userAuthLocal.setPassword(password);
userAuthLocal.setAccountType(AccountType.EMAIL.getType());
userAuthLocal.setStatus(AuthStatus.NORMAL.getStatus());
userAuthLocalService.save(userAuthLocal);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void bindMobile(String mobile, String verifyCode, String userId) throws UserServiceException {
// 1.检测验证码
String realVerifyCode = redisHelper.get(RedisKey.MOBILE_VERIFY_CODE(mobile));
if (StringUtils.isEmpty(realVerifyCode) || !realVerifyCode.equals(verifyCode)) {
throw new UserServiceException(UserErrorCode.BINDING_MOBILE_VERIFY_CODE_ERROR);
}
// 2.删除验证码
redisHelper.del(RedisKey.MOBILE_VERIFY_CODE(mobile));
// 3.检测该手机号是否已被占用
UserAuthLocal userAuthLocal = userAuthLocalService.getByAccount(mobile);
if (null != userAuthLocal) {
throw new UserServiceException(UserErrorCode.MOBILE_REGISTERED);
}
// 4.查找该用户的其他本地认证信息
String password = getPasswordInUserAuthLocal(userId);
// 5.绑定手机号
userAuthLocal = new UserAuthLocal();
userAuthLocal.setUserId(userId);
userAuthLocal.setAccount(mobile);
userAuthLocal.setPassword(password);
userAuthLocal.setAccountType(AccountType.MOBILE.getType());
userAuthLocal.setStatus(AuthStatus.NORMAL.getStatus());
userAuthLocalService.save(userAuthLocal);
}
private String getPasswordInUserAuthLocal(String userId) {
QueryWrapper<UserAuthLocal> userAuthLocalQueryWrapper = new QueryWrapper<>();
userAuthLocalQueryWrapper.eq("user_id", userId);
List<UserAuthLocal> userAuthLocalList = userAuthLocalService.list(userAuthLocalQueryWrapper);
if (!CollectionUtils.isEmpty(userAuthLocalList)) {
for (UserAuthLocal ual : userAuthLocalList) {
if (!StringUtils.isEmpty(ual.getPassword())) {
return ual.getPassword();
}
}
}
return null;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment