目录
1.获取验证码
1.2获取验证码
2.校验验证码
2.1Tken介绍
2.3远程调用根据手机号查询用户和添加的方法
3.今天遇到的小问题
具体步骤:
1.1获取验证码
1.2.校验验证码
获取验证码我用的是阿里云获取验证码
我把他抽取成了一个工具类
SmsProperties 这里设置了自动装配类 @ConfigurationProperties(prefix = "tanhua.sms")
@Data
@ConfigurationProperties(prefix = "tanhua.sms")
public class SmsProperties {
private String smsSignId; //签名
private String templateId; //模板
private String appcode;
}
配置文件spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tanhua.autoconfig.TanhuaAutoConfiguration
SmsTemplate 类
public class SmsTemplate {
private SmsProperties properties;
public SmsTemplate (SmsProperties properties) {
this.properties = properties;
}
public void sendSms(String mobile,String code) {
//请求连接
String host = "https://gyytz.market.alicloudapi.com/sms/smsSend";
//拼装请求体
Map querys = new HashMap();
querys.put("mobile", mobile);
querys.put("param", "**code**:"+code+",**minute**:5");
querys.put("smsSignId", properties.getSmsSignId());
querys.put("templateId", properties.getTemplateId());
try {
String result = HttpRequest.post(host)
.header(Header.AUTHORIZATION, "APPCODE " + properties.getAppcode())//头信息,多个头信息多次调用此方法即可
.form(querys)//表单内容
.timeout(20000)//超时,毫秒
.execute().body();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
要发送验证码就直接可以调用工具类的方式即可
controller代码 没什么可说的,就是把json格式的参数转换成字符串
/**
*
* @param map 手机号是jsno格式的
* @return 返回一个状态吗
*/
@PostMapping("/login")
public ResponseEntity login(@RequestBody Map map){
String phone = (String) map.get("phone");
userService.sendMsg(phone);
return ResponseEntity.status(200).body("成功");
}
Service层
1.先 调用template发送短信
smsTemplate.sendSms(phone, code);
2.把验证码存到redis里面方便验证
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private SmsTemplate smsTemplate;
@DubboReference
private UserApi userApi;
//获取验证码
public void sendMsg(String phone) {
//1、生成验证码(6位数字)
String code = RandomStringUtils.randomNumeric(6);
// String code ="123456";
//2、调用template发送短信
smsTemplate.sendSms(phone, code);
//3、存入redis
redisTemplate.opsForValue().set("CHECK_CODE_" + phone, code, Duration.ofMinutes(5));//验证码失效时间
//4、构建返回值
controller层 这一层没啥好说的
/** 用户登录
* /user/loginVerification 验证码校验
* phone 手机号
* verificationCode 验证码
*
*/
@PostMapping("/loginVerification")
public ResponseEntity loginVerification(@RequestBody Map map){
String phone = (String) map.get("phone");
String code = (String) map.get("verificationCode");
return userService.loginVerification(phone, code);//校验手机号
}
service层 这一层就有点东西了
1.先去Redis里面根据手机号为key的形式获取到验证码值然后对比
2.如果跟用户的验证码保持一致就调用根据手机号查询用户的方法,反之就报500异常(如果通过了之后记得要删除redis里面的缓存)
3.根据手机号查询用户,如果用户对象是空就帮他重创建一个,并且获取他的id
4.把用户手机号和id传递给Tken工具类生成一个Tken
5.把生成的Tken值返回出去
public ResponseEntity loginVerification(String phone, String code) {
//从Redis里面获取验证码
String vlue = redisTemplate.opsForValue().get("CHECK_CODE_" + phone);
//1.判断验证码是否正确、
if (code.isEmpty()||!code.equals(vlue)) {
//2.验证码不正确或者为空抛出一个异常
return ResponseEntity.status(500).body(ErrorResult.loginError());
}
redisTemplate.delete("CHECK_CODE_" + phone);// 清除redis中的验证码数据
//3.登录成功查询用户
User user = userApi.findByMobile(phone);
//查询用户是否为空,为空就是没注册,然后自动注册
boolean isNew = false;
if (user == null) {
user = new User();
user.setMobile(phone);
user.setPassword(DigestUtils.md5Hex("123456"));
Long userId = userApi.save(user);
user.setId(userId);
isNew = true;
} //4.通过JWT生成Token
Map map = new HashMap();
map.put("id", user.getId());
map.put("mobile", phone);
String token = JwtUtils.getToken(map);
//5、构造返回值
Map retmap = new HashMap();
retmap.put("token", token);
retmap.put("isNew", isNew);
return ResponseEntity.ok(retmap);
}
JSON Web Token简称JWT,用于对应用程序上用户进行身份验证的标记。使用 JWTS 之后不需要保存用户的 cookie 或其他session数据,同时可保证应用程序的安全。
JWT是经过加密处理与校验处理的字符串,形式为:A.B.C
–A由JWT头部信息header加密得到
–B由JWT用到的身份验证信息JSON数据加密得到
–C由A和B加密得到,是校验部分
–官方测试网站: JSON Web Tokens - jwt.io
public class JwtUtils {
// TOKEN的有效期1小时(S)
private static final int TOKEN_TIME_OUT = 3_600;
// 加密KEY
private static final String TOKEN_SECRET = "itcast";
// 生成Token
public static String getToken(Map params){
long currentTime = System.currentTimeMillis();
return Jwts.builder()
.signWith(SignatureAlgorithm.HS512, TOKEN_SECRET) //加密方式
.setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //过期时间戳
.addClaims(params) 传递过来的要封装成Tken的值,为map格式
.compact();
}
/**
* 获取Token中的claims信息
*/
private static Claims getClaims(String token) {
return Jwts.parser()
.setSigningKey(TOKEN_SECRET)
.parseClaimsJws(token).getBody();
}
/**
* 是否有效 true-有效,false-失效
*/
public static boolean verifyToken(String token) {
if(StringUtils.isEmpty(token)) {
return false;
}
try {
Claims claims = Jwts.parser()
.setSigningKey("itcast")
.parseClaimsJws(token)
.getBody();
}catch (Exception e) {
return false;
}
return true;
}
UserApi接口 远程调用调他就完事了 (在这里我们是直接抽取成了api方法直接远程调用)
//用户Api
public interface UserApi {
//根据用户手机号查找用户
User findByMobile(String mobile);
//添加一个用户。并且返回他的用户id
Long save(User user);
}
UserApiImpl实现Api
@DubboService //暴露远程调用的接口
public class UserApiImpl implements UserApi{
@Autowired
private UserMapper userMapper;
/**
* 根据用户手机号IU查找用户
* @param mobile 手机号
* @return 用户信息
*/
@Override
public User findByMobile(String mobile) {
QueryWrapper qw = new QueryWrapper<>();
qw.eq("mobile",mobile);
return userMapper.selectOne(qw);
* @param user 要存入的用户数据
* @return 返回一个用户Id
*/
@Override
public Long save(User user) {
userMapper.insert(user);
return user.getId();
}
}
操作数据库直接用Mybatis plus
1.获取验证码登录的时候总是会显示验证码错误,可是我明明已经设置了验证码是123456的默认值
问题解决
2.远程调用的时候的细节问题
问题排查与解决:这里的注解我不小心写成了@Autowired注入了
应该改成DubboReference才对的