add 增加 短信登录 与 小程序登录 示例

This commit is contained in:
疯狂的狮子Li
2022-03-23 01:02:07 +08:00
parent 641a15158d
commit bb479c436a
13 changed files with 250 additions and 21 deletions

View File

@@ -2,12 +2,13 @@ package com.ruoyi.auth.controller;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.nacos.api.common.Constants;
import com.ruoyi.auth.form.LoginBody;
import com.ruoyi.auth.form.RegisterBody;
import com.ruoyi.auth.form.SmsLoginBody;
import com.ruoyi.auth.service.SysLoginService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.satoken.utils.LoginHelper;
import com.ruoyi.system.api.model.LoginUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
@@ -17,6 +18,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;
import java.util.HashMap;
import java.util.Map;
@@ -45,6 +47,38 @@ public class TokenController {
return R.ok(rspMap);
}
/**
* 短信登录(示例)
*
* @param smsLoginBody 登录信息
* @return 结果
*/
@ApiOperation("短信登录(示例)")
@PostMapping("/smsLogin")
public R<Map<String, Object>> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) {
Map<String, Object> ajax = new HashMap<>();
// 生成令牌
String token = sysLoginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode());
ajax.put(Constants.TOKEN, token);
return R.ok(ajax);
}
/**
* 小程序登录(示例)
*
* @param xcxCode 小程序code
* @return 结果
*/
@ApiOperation("短信登录(示例)")
@PostMapping("/xcxLogin")
public R<Map<String, Object>> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) {
Map<String, Object> ajax = new HashMap<>();
// 生成令牌
String token = sysLoginService.xcxLogin(xcxCode);
ajax.put(Constants.TOKEN, token);
return R.ok(ajax);
}
@ApiOperation("登出方法")
@DeleteMapping("logout")
public R<Void> logout() {

View File

@@ -0,0 +1,33 @@
package com.ruoyi.auth.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 短信登录对象
*
* @author Lion Li
*/
@Data
@ApiModel("短信登录对象")
public class SmsLoginBody {
/**
* 用户名
*/
@NotBlank(message = "{user.phonenumber.not.blank}")
@ApiModelProperty(value = "用户手机号")
private String phonenumber;
/**
* 用户密码
*/
@NotBlank(message = "{sms.code.not.blank}")
@ApiModelProperty(value = "短信验证码")
private String smsCode;
}

View File

@@ -75,6 +75,57 @@ public class SysLoginService {
return StpUtil.getTokenValue();
}
public String smsLogin(String phonenumber, String smsCode) {
// 通过手机号查找用户
LoginUser userInfo = remoteUserService.getUserInfoByPhonenumber(phonenumber);
// 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
Integer errorNumber = RedisUtils.getCacheObject(CacheConstants.LOGIN_ERROR + userInfo.getUsername());
// 锁定时间内登录 则踢出
if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(CacheConstants.LOGIN_ERROR_NUMBER)) {
recordLogininfor(userInfo.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.exceed", CacheConstants.LOGIN_ERROR_LIMIT_TIME));
throw new UserException("sms.code.retry.limit.exceed", CacheConstants.LOGIN_ERROR_LIMIT_TIME);
}
if (!validateSmsCode(phonenumber, smsCode)) {
// 是否第一次
errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
// 达到规定错误次数 则锁定登录
if (errorNumber.equals(CacheConstants.LOGIN_ERROR_NUMBER)) {
RedisUtils.setCacheObject(CacheConstants.LOGIN_ERROR + userInfo.getUsername(), errorNumber, CacheConstants.LOGIN_ERROR_LIMIT_TIME, TimeUnit.MINUTES);
recordLogininfor(userInfo.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.exceed", CacheConstants.LOGIN_ERROR_LIMIT_TIME));
throw new UserException("sms.code.retry.limit.exceed", CacheConstants.LOGIN_ERROR_LIMIT_TIME);
} else {
// 未达到规定错误次数 则递增
RedisUtils.setCacheObject(CacheConstants.LOGIN_ERROR + userInfo.getUsername(), errorNumber);
recordLogininfor(userInfo.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.count", errorNumber));
throw new UserException("sms.code.retry.limit.count", errorNumber);
}
}
// 登录成功 清空错误次数
RedisUtils.deleteObject(CacheConstants.LOGIN_ERROR + userInfo.getUsername());
// 生成token
LoginHelper.loginByDevice(userInfo, DeviceType.APP);
recordLogininfor(userInfo.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
return StpUtil.getTokenValue();
}
public String xcxLogin(String xcxCode) {
// xcxCode 为 小程序调用 wx.login 授权后获取
// todo 自行实现 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
String openid = "";
LoginUser userInfo = remoteUserService.getUserInfoByOpenid(openid);
// 生成token
LoginHelper.loginByDevice(userInfo, DeviceType.XCX);
recordLogininfor(userInfo.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
return StpUtil.getTokenValue();
}
public void logout(String loginName) {
recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success"));
}
@@ -122,4 +173,12 @@ public class SysLoginService {
}
remoteLogService.saveLogininfor(logininfor);
}
/**
* 校验短信验证码
*/
private boolean validateSmsCode(String phonenumber, String smsCode) {
// todo 此处使用手机号查询redis验证码与参数验证码是否一致 用户自行实现
return true;
}
}