写在开局 : 本篇文章 和 美食社交的认证授权中心同步, 实现简单功能:
[用户登录与注册], 同时附上认证授权的文章地址:认证授权文章链接
1. 发送验证码
1.2 Redis 配置类
package com.itkaka.diners.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisTemplateConfiguration {
/**
* redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
*
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置key和value的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
1.3 公共枚举类
package com.itkaka.commons.constant;
import lombok.Getter;
@Getter
public enum RedisKeyConstant {
verify_code("verify_code:", "验证码"),
private String key;
private String desc;
RedisKeyConstant(String key, String desc) {
this.key = key;
this.desc = desc;
}
}
1.4 Service业务层代码
package com.itkaka.diners.service;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.itkaka.commons.constant.RedisKeyConstant;
import com.itkaka.commons.utils.AssertUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* 发送验证码业务逻辑层
*/
@Service
public class SendVerifyCodeService {
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 发送验证码
*
* @param phone
*/
public void send(String phone) {
// 检查非空
AssertUtil.isNotEmpty(phone, "手机号不能为空");
// 根据手机号查询是否已生成验证码,已生成直接返回
if (!checkCodeIsExpired(phone)) {
return;
}
// 生成 6 位验证码
String code = RandomUtil.randomNumbers(6);
// 调用短信服务发送短信(忽略)
// 发送成功,将 code 保存到 Redis,失效时间 60s
String key = RedisKeyConstant.verify_code.getKey() + phone;
redisTemplate.opsForValue().set(key, code, 60, TimeUnit.SECONDS);
}
/**
* 根据手机号查询是否已生成验证码
*
* @param phone
* @return
*/
private boolean checkCodeIsExpired(String phone) {
String key = RedisKeyConstant.verify_code.getKey() + phone;
String code = redisTemplate.opsForValue().get(key);
return StrUtil.isBlank(code) ? true : false;
}
/**
* 根据手机号获取验证码
*
* @param phone
* @return
*/
public String getCodeByPhone(String phone) {
String key = RedisKeyConstant.verify_code.getKey() + phone;
return redisTemplate.opsForValue().get(key);
}
}
1.5 Controller控制层代码
package com.itkaka.diners.controller;
import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.utils.ResultInfoUtil;
import com.itkaka.diners.service.SendVerifyCodeService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* 发送验证码控制层
*/
@RestController
public class SendVerifyCodeController {
@Resource
private HttpServletRequest request;
@Resource
private SendVerifyCodeService sendVerifyCodeService;
/**
* 发送验证码
*
* @param phone
* @return
*/
@GetMapping("send")
public ResultInfo<String> send(String phone) {
sendVerifyCodeService.send(phone);
return ResultInfoUtil.buildSuccess("发送成功", request.getServletPath());
}
}
1.6 网关设置
白名单放行发送验证码接口
server:
port: 80 # 端口
spring:
application:
name: fs_gateway # 应用名
cloud:
gateway:
discovery:
locator:
enabled: true # 开启配置注册中心进行路由功能
lower-case-service-id: true # 将服务名称转小写
routes:
- id: fs_diners
uri: lb://fs_diners
predicates:
- Path=/diners/**
filters:
- StripPrefix=1
- id: fs_oauth
uri: lb://fs_oauth
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
secure:
ignore:
urls: # 配置白名单路径
- /actuator/**
- /auth/oauth/**
- /diners/signin
- /diners/send
# 配置 Eureka Server 注册中心
eureka:
instance:
# 开启 ip 注册
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${server.port}
client:
service-url:
defaultZone: http://localhost:8090/eureka/
# 配置日志
logging:
pattern:
console: '%d{2100-01-01 13:14:00.666} [%thread] %-5level %logger{50} - %msg%n'
1.7 测试
访问:http://localhost/diners/send?phone=12311112222
返回结果:
{
"code": 1,
"message": "Successful.",
"path": "发送成功",
"data": "/send"
}
2. 注册
2.1 是否已注册
2.1.1 Mapper持久层
package com.itkaka.diners.mapper;
import com.itkaka.commons.model.dto.DinersDTO;
import com.itkaka.commons.model.pojo.Diners;
import com.itkaka.commons.model.vo.ShortDinerInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 食客 Mapper
*/
public interface DinersMapper {
/**
* 根据手机号查询食客信息
*
* @param phone
* @return
*/
@Select("select id, username, phone, email, is_valid " +
" from t_diners where phone = #{phone}")
Diners selectByPhone(@Param("phone") String phone);
/**
* 根据用户名查询食客信息
*
* @param username
* @return
*/
@Select("select id, username, phone, email, is_valid " +
" from t_diners where username = #{username}")
Diners selectByUsername(@Param("username") String username);
/**
* 新增食客信息
*
* @param dinersDTO
* @return
*/
@Insert("insert into " +
" t_diners (username, password, phone, roles, is_valid, create_date, update_date) " +
" values (#{username}, #{password}, #{phone}, \"ROLE_USER\", 1, now(), now())")
int save(DinersDTO dinersDTO);
/**
* 根据 ID 集合查询食客信息
*
* @param ids
* @return
*/
@Select("<script> " +
" select id, nickname, avatar_url from t_diners " +
" where is_valid = 1 and id in " +
" <foreach item='id' collection='ids' open='(' separator=',' close=')'> " +
" #{id} " +
" </foreach> " +
" </script>")
List<ShortDinerInfo> findByIds(@Param("ids") String[] ids);
}
2.1.2 Service
package com.itkaka.diners.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.itkaka.commons.constant.ApiConstant;
import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.model.dto.DinersDTO;
import com.itkaka.commons.model.pojo.Diners;
import com.itkaka.commons.model.vo.ShortDinerInfo;
import com.itkaka.commons.utils.AssertUtil;
import com.itkaka.commons.utils.ResultInfoUtil;
import com.itkaka.diners.config.OAuthClientConfiguration;
import com.itkaka.diners.config.OAuthClientConfiguration;
import com.itkaka.diners.mapper.DinersMapper;
import com.itkaka.diners.model.domain.OAuthDinerInfo;
import com.itkaka.diners.model.vo.LoginDinerInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
/**
* 食客服务业务逻辑层
*/
@Service
public class DinersService {
@Resource
private RestTemplate restTemplate;
@Value("${service.name.fs_oauth-server}")
private String oauthServerName;
@Resource
private OAuthClientConfiguration oAuthClientConfiguration;
@Resource
private DinersMapper dinersMapper;
@Resource
private com.itkaka.diners.service.SendVerifyCodeService sendVerifyCodeService;
/**
* 登录
*
* @param account 账号信息:用户名或手机或邮箱
* @param password 密码
* @param path 请求路径
* @return
*/
public ResultInfo signIn(String account, String password, String path) {
// 参数校验
AssertUtil.isNotEmpty(account, "请输入登录账户");
AssertUtil.isNotEmpty(password, "请输入登录密码");
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// 构建请求体
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("username", account);
body.add("password", password);
body.setAll(BeanUtil.beanToMap(oAuthClientConfiguration));
// 设置Authorization
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
// 设置BasicAuthorization
restTemplate.getInterceptors().add(
new BasicAuthenticationInterceptor(oAuthClientConfiguration.getClientId(),
oAuthClientConfiguration.getSecret())
);
// 发送请求
ResponseEntity<ResultInfo> result = restTemplate.postForEntity(oauthServerName + "oauth/token",
entity, ResultInfo.class);
// 处理返回结果
AssertUtil.isTrue(result.getStatusCode() != HttpStatus.OK, "登录失败!");
ResultInfo resultInfo = result.getBody();
if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {
// 登录失败
resultInfo.setData(resultInfo.getMessage());
return resultInfo;
}
OAuthDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),
new OAuthDinerInfo(), false);
LoginDinerInfo loginDinerInfo = new LoginDinerInfo();
loginDinerInfo.setToken(dinerInfo.getAccessToken());
loginDinerInfo.setNickname(dinerInfo.getNickname());
loginDinerInfo.setAvatarUrl(dinerInfo.getAvatarUrl());
return ResultInfoUtil.buildSuccess(path, loginDinerInfo);
}
/**
* 校验手机号是否已注册
*
* @param phone
*/
public void checkPhoneIsRegistered(String phone) {
AssertUtil.isNotEmpty(phone, "手机号不能为空");
Diners diners = dinersMapper.selectByPhone(phone);
AssertUtil.isTrue(diners == null, "该手机号未注册");
AssertUtil.isTrue(diners.getIsValid() == 0, "该用户已锁定,请先解锁");
}
/**
* 用户注册
*
* @param dinersDTO
* @param path
* @return
*/
public ResultInfo register(DinersDTO dinersDTO, String path) {
// 参数非空校验
String username = dinersDTO.getUsername();
AssertUtil.isNotEmpty(username, "请输入用户名");
String password = dinersDTO.getPassword();
AssertUtil.isNotEmpty(username, "请输入密码");
String phone = dinersDTO.getPhone();
AssertUtil.isNotEmpty(username, "请输入手机号");
String verifyCode = dinersDTO.getVerifyCode();
AssertUtil.isNotEmpty(username, "请输入验证码");
// 获取验证码
String code = sendVerifyCodeService.getCodeByPhone(phone);
// 验证码是否已过期
AssertUtil.isNotEmpty(code, "验证码已过期,请重新发送");
// 校验验证码一致性
AssertUtil.isTrue(!dinersDTO.getVerifyCode().equals(code),
"验证码不一致,请重新输入");
// 验证用户名是否已注册
Diners diners = dinersMapper.selectByUsername(username.trim());
AssertUtil.isTrue(diners != null, "用户名已存在,请重新输入");
// 注册
// 密码加密
dinersDTO.setPassword(DigestUtil.md5Hex(password.trim()));
dinersMapper.save(dinersDTO);
// 自动登录
return signIn(username.trim(), password.trim(), path);
}
/**
* 根据食客 ID 集合查询食客信息
*
* @param ids 主键 id 集合,多个以逗号分隔,逗号之间不用空格
* @return
*/
public List<ShortDinerInfo> findByIds(String ids) {
AssertUtil.isNotEmpty(ids);
String[] idArr = ids.split(",");
List<ShortDinerInfo> dinerInfos = dinersMapper.findByIds(idArr);
return dinerInfos;
}
}
2.1.3 Controller
package com.itkaka.diners.controller;
import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.model.dto.DinersDTO;
import com.itkaka.commons.model.vo.ShortDinerInfo;
import com.itkaka.commons.utils.ResultInfoUtil;
import com.itkaka.diners.service.DinersService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* 食客服务控制层
*/
@RestController
@Api(tags = "食客相关接口")
public class DinersController {
@Resource
private DinersService dinersService;
@Resource
private HttpServletRequest request;
/**
* 登录
*
* @param account
* @param password
* @return
*/
@GetMapping("signin")
public ResultInfo signIn(String account, String password) {
return dinersService.signIn(account, password, request.getServletPath());
}
/**
* 校验手机号是否已注册
*
* @param phone
* @return
*/
@GetMapping("checkPhone")
public ResultInfo checkPhone(String phone) {
dinersService.checkPhoneIsRegistered(phone);
return ResultInfoUtil.buildSuccess(request.getServletPath());
}
/**
* 用户注册
*
* @param dinersDTO
* @return
*/
@PostMapping("register")
public ResultInfo register(@RequestBody DinersDTO dinersDTO) {
return dinersService.register(dinersDTO, request.getServletPath());
}
/**
* 根据食客 ID 集合查询食客信息
*
* @param ids 主键 id 集合,多个以逗号分隔,逗号之间不用空格
* @return
*/
@GetMapping("findByIds")
public ResultInfo<List<ShortDinerInfo>> findByIds(String ids) {
List<ShortDinerInfo> dinerInfos = dinersService.findByIds(ids);
return ResultInfoUtil.buildSuccess(request.getServletPath(), dinerInfos);
}
}
2.1.4 网关配置
放行校验手机号接口
secure:
ignore:
urls: # 配置白名单路径
- /actuator/**
- /auth/oauth/**
- /diners/signin
- /diners/send
- /diners/checkPhone
测试
访问:http://localhost/diners/checkPhone?phone=12311112222
返回结果(已注册):
{
"code": 1,
"message": "Successful.",
"path": "/checkPhone",
"data": null
}
返回结果 (未注册)
{
"timestamp": "2020-11-15T10:16:23.815+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "",
"path": "/checkPhone"
}
2.2 全局异常处理
package com.itkaka.diners.handler;
import com.itkaka.commons.exception.ParameterException;
import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.utils.ResultInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@RestControllerAdvice // 将输出的内容写入 ResponseBody 中
@Slf4j
public class GlobalExceptionHandler {
@Resource
private HttpServletRequest request;
@ExceptionHandler(ParameterException.class)
public ResultInfo<Map<String, String>> handlerParameterException(ParameterException ex) {
String path = request.getRequestURI();
ResultInfo<Map<String, String>> resultInfo =
ResultInfoUtil.buildError(ex.getErrorCode(), ex.getMessage(), path);
return resultInfo;
}
@ExceptionHandler(Exception.class)
public ResultInfo<Map<String, String>> handlerException(Exception ex) {
log.info("未知异常:{}", ex);
String path = request.getRequestURI();
ResultInfo<Map<String, String>> resultInfo = ResultInfoUtil.buildError(path);
return resultInfo;
}
}
测试
{
"code": 0,
"message": "该手机号未注册",
"path": "/checkPhone",
"data": null
}
2.3 完成注册
2.3.1 DTO (数据传输对象)
package com.itkaka.commons.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@ApiModel(description = "注册用户信息")
public class DinersDTO implements Serializable {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private String password;
@ApiModelProperty("手机号")
private String phone;
@ApiModelProperty("验证码")
private String verifyCode;
}
2.3.2 Mapper
/**
* 根据用户名查询食客信息
*/
@Select("select id, username, phone, email, is_valid " +
" from t_diners where username = #{username}")
Diners selectByUsername(@Param("username") String username);
/**
* 新增食客信息
*/
@Insert("insert into " +
" t_diners (username, password, phone, roles, is_valid, create_date, update_date) " +
" values (#{username}, #{password}, #{phone}, \"ROLE_USER\", 1, now(), now())")
int save(DinersDTO dinersDTO);
2.3.3 Service
SendVerifyCodeService.java
package com.itkaka.diners.service;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.itkaka.commons.constant.RedisKeyConstant;
import com.itkaka.commons.utils.AssertUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* 发送验证码业务逻辑层
*/
@Service
public class SendVerifyCodeService {
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 发送验证码
*
* @param phone
*/
public void send(String phone) {
// 检查非空
AssertUtil.isNotEmpty(phone, "手机号不能为空");
// 根据手机号查询是否已生成验证码,已生成直接返回
if (!checkCodeIsExpired(phone)) {
return;
}
// 生成 6 位验证码
String code = RandomUtil.randomNumbers(6);
// 调用短信服务发送短信(忽略)
// 发送成功,将 code 保存到 Redis,失效时间 60s
String key = RedisKeyConstant.verify_code.getKey() + phone;
redisTemplate.opsForValue().set(key, code, 60, TimeUnit.SECONDS);
}
/**
* 根据手机号查询是否已生成验证码
*
* @param phone
* @return
*/
private boolean checkCodeIsExpired(String phone) {
String key = RedisKeyConstant.verify_code.getKey() + phone;
String code = redisTemplate.opsForValue().get(key);
return StrUtil.isBlank(code) ? true : false;
}
/**
* 根据手机号获取验证码
*
* @param phone
* @return
*/
public String getCodeByPhone(String phone) {
String key = RedisKeyConstant.verify_code.getKey() + phone;
return redisTemplate.opsForValue().get(key);
}
}
DinersService.java
package com.itkaka.diners.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.itkaka.commons.constant.ApiConstant;
import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.model.dto.DinersDTO;
import com.itkaka.commons.model.pojo.Diners;
import com.itkaka.commons.model.vo.ShortDinerInfo;
import com.itkaka.commons.utils.AssertUtil;
import com.itkaka.commons.utils.ResultInfoUtil;
import com.itkaka.diners.config.OAuthClientConfiguration;
import com.itkaka.diners.config.OAuthClientConfiguration;
import com.itkaka.diners.mapper.DinersMapper;
import com.itkaka.diners.model.domain.OAuthDinerInfo;
import com.itkaka.diners.model.vo.LoginDinerInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
/**
* 食客服务业务逻辑层
*/
@Service
public class DinersService {
@Resource
private RestTemplate restTemplate;
@Value("${service.name.fs_oauth-server}")
private String oauthServerName;
@Resource
private OAuthClientConfiguration oAuthClientConfiguration;
@Resource
private DinersMapper dinersMapper;
@Resource
private com.itkaka.diners.service.SendVerifyCodeService sendVerifyCodeService;
/**
* 登录
*
* @param account 账号信息:用户名或手机或邮箱
* @param password 密码
* @param path 请求路径
* @return
*/
public ResultInfo signIn(String account, String password, String path) {
// 参数校验
AssertUtil.isNotEmpty(account, "请输入登录账户");
AssertUtil.isNotEmpty(password, "请输入登录密码");
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// 构建请求体
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("username", account);
body.add("password", password);
body.setAll(BeanUtil.beanToMap(oAuthClientConfiguration));
// 设置Authorization
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
// 设置BasicAuthorization
restTemplate.getInterceptors().add(
new BasicAuthenticationInterceptor(oAuthClientConfiguration.getClientId(),
oAuthClientConfiguration.getSecret())
);
// 发送请求
ResponseEntity<ResultInfo> result = restTemplate.postForEntity(oauthServerName + "oauth/token",
entity, ResultInfo.class);
// 处理返回结果
AssertUtil.isTrue(result.getStatusCode() != HttpStatus.OK, "登录失败!");
ResultInfo resultInfo = result.getBody();
if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {
// 登录失败
resultInfo.setData(resultInfo.getMessage());
return resultInfo;
}
OAuthDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),
new OAuthDinerInfo(), false);
LoginDinerInfo loginDinerInfo = new LoginDinerInfo();
loginDinerInfo.setToken(dinerInfo.getAccessToken());
loginDinerInfo.setNickname(dinerInfo.getNickname());
loginDinerInfo.setAvatarUrl(dinerInfo.getAvatarUrl());
return ResultInfoUtil.buildSuccess(path, loginDinerInfo);
}
/**
* 校验手机号是否已注册
*
* @param phone
*/
public void checkPhoneIsRegistered(String phone) {
AssertUtil.isNotEmpty(phone, "手机号不能为空");
Diners diners = dinersMapper.selectByPhone(phone);
AssertUtil.isTrue(diners == null, "该手机号未注册");
AssertUtil.isTrue(diners.getIsValid() == 0, "该用户已锁定,请先解锁");
}
/**
* 用户注册
*
* @param dinersDTO
* @param path
* @return
*/
public ResultInfo register(DinersDTO dinersDTO, String path) {
// 参数非空校验
String username = dinersDTO.getUsername();
AssertUtil.isNotEmpty(username, "请输入用户名");
String password = dinersDTO.getPassword();
AssertUtil.isNotEmpty(username, "请输入密码");
String phone = dinersDTO.getPhone();
AssertUtil.isNotEmpty(username, "请输入手机号");
String verifyCode = dinersDTO.getVerifyCode();
AssertUtil.isNotEmpty(username, "请输入验证码");
// 获取验证码
String code = sendVerifyCodeService.getCodeByPhone(phone);
// 验证码是否已过期
AssertUtil.isNotEmpty(code, "验证码已过期,请重新发送");
// 校验验证码一致性
AssertUtil.isTrue(!dinersDTO.getVerifyCode().equals(code),
"验证码不一致,请重新输入");
// 验证用户名是否已注册
Diners diners = dinersMapper.selectByUsername(username.trim());
AssertUtil.isTrue(diners != null, "用户名已存在,请重新输入");
// 注册
// 密码加密
dinersDTO.setPassword(DigestUtil.md5Hex(password.trim()));
dinersMapper.save(dinersDTO);
// 自动登录
return signIn(username.trim(), password.trim(), path);
}
/**
* 根据食客 ID 集合查询食客信息
*
* @param ids 主键 id 集合,多个以逗号分隔,逗号之间不用空格
* @return
*/
public List<ShortDinerInfo> findByIds(String ids) {
AssertUtil.isNotEmpty(ids);
String[] idArr = ids.split(",");
List<ShortDinerInfo> dinerInfos = dinersMapper.findByIds(idArr);
return dinerInfos;
}
}
2.3.4 Controller
/**
* 用户注册
*
* @param dinersDTO
* @return
*/
@PostMapping("register")
public ResultInfo register(@RequestBody DinersDTO dinersDTO) {
return dinersService.register(dinersDTO, request.getServletPath());
}
2.3.5 网关配置
放行注册接口
secure:
ignore:
urls: # 配置白名单路径
- /actuator/**
- /auth/oauth/**
- /diners/signin
- /diners/send
- /diners/checkPhone
- /diners/register
2.3.6 测试
先访问:http://localhost/diners/checkPhone?phone=12311113333
返回结果:
{
"code": 0,
"message": "该手机号未注册",
"path": "/checkPhone",
"data": null
}
再访问:http://localhost/diners/send?phone=12311113333
返回结果(Redis 查看验证码):
{
"code": 1,
"message": "Successful.",
"path": "发送成功",
"data": "/send"
}
再访问:http://localhost/diners/register
请求参数:
{
"username": "zhangsan",
"password": "123456",
"phone": "12311113333",
"verifyCode": "833275"
}
返回结果:
{
"code": 1,
"message": "Successful.",
"path": "/register",
"data": {
"nickname": null,
"token": "4323c187-5ffa-4e45-a3a3-e7cdff32145d",
"avatarUrl": null
}
}
这是用户登录注册流程图,该图借鉴来源: 哈喽沃德先生的主页 -->哈喽沃德先生主页 ,可以在CSDN,知乎等平台搜索即可;
👉 💕美好的一天,从现在开始,大家一起努力!后续更新持续更新,码字不易,麻烦大家小手一点 , 点赞或关注 , 感谢大家的支持!! 🌙