H5的登录、注册

pull/1/head
chuzhichao 2 years ago
parent fe1a2b1cdf
commit 525dc60d3c

@ -0,0 +1,68 @@
package com.ruoyi.web.core.config;
import com.cyl.ums.domain.Member;
import com.cyl.ums.service.MemberService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.model.LoginMember;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.framework.config.LocalDataUtil;
import com.ruoyi.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class H5MemberInterceptor extends HandlerInterceptorAdapter {
@Autowired
private TokenService tokenService;
@Autowired
private MemberService memberService;
private static String[] WHITE_PATHS = {
"/h5/sms/login",
"/h5/account/login",
"/h5/register",
"/h5/validate"
};
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestUri = request.getRequestURI();
boolean flag = true;
if (!requestUri.startsWith("/h5/")) {
return super.preHandle(request, response, handler);
}
for (String s : WHITE_PATHS) {
if (requestUri.startsWith(s)) {
flag = false;
break;
}
}
if (!flag) {
return super.preHandle(request, response, handler);
}
LoginMember loginMember = tokenService.getLoginMember(request);
if (loginMember == null) {
throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
}
tokenService.verifyMemberToken(loginMember);
//获取会员信息
Member member = memberService.selectById(loginMember.getMemberId());
if (member == null || member.getStatus() == 0) {
throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
}
//将会员信息存放至全局
LocalDataUtil.setVar(Constants.MEMBER_INFO, member);
return super.preHandle(request, response, handler);
}
}

@ -0,0 +1,23 @@
package com.ruoyi.web.core.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@Slf4j
public class MvcConfig extends WebMvcConfigurerAdapter {
@Bean
public H5MemberInterceptor memberInterceptor() {
return new H5MemberInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(memberInterceptor());
}
}

@ -121,6 +121,7 @@ token:
secret: abcdefghijkomnopqrstuvwxyx
# 令牌有效期默认30分钟
expireTime: 30
memberExpireTime: 30
# mybatis-plus 配置
mybatis-plus:
# 搜索指定包别名

@ -2,6 +2,11 @@ package com.fjp.lc.test.service;
import com.cyl.ums.service.MemberCartService;
import com.ruoyi.RuoYiApplication;
import com.ruoyi.common.config.properties.SmsProperties;
import com.ruoyi.common.core.sms.AliyunSmsTemplate;
import com.ruoyi.common.core.sms.SmsTemplate;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -9,14 +14,35 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.HashMap;
import java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = RuoYiApplication.class)
@ActiveProfiles("dev")
@Slf4j
public class ServiceTest {
@Autowired
private MemberCartService memberCartService;
@Autowired
private SmsProperties smsProperties;
@Test
public void test1() {
memberCartService.mineCartNum();
}
@Test
public void test2(){
System.out.println(smsProperties);
if (!smsProperties.getEnabled()) {
throw new RuntimeException("没有开启短信服务");
}
Map<String, String> map = new HashMap<>(1);
map.put("code", "1234");
SmsTemplate smsTemplate = new AliyunSmsTemplate(smsProperties);
Object send = smsTemplate.send("15706259078", "SMS_146125046", map);
log.info("短信发送结果:" + send);
}
}

@ -68,6 +68,8 @@ public class Constants
* redis key
*/
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
public static final String LOGIN_MEMBER_TOKEN_KEY = "login_member_tokens:";
public static final String MEMBER_INFO = "member_info";
/**
* redis key
@ -98,6 +100,7 @@ public class Constants
*
*/
public static final String LOGIN_USER_KEY = "login_user_key";
public static final String LOGIN_MEMBER_KEY = "login_member_key";
/**
* ID

@ -0,0 +1,13 @@
package com.ruoyi.common.core.domain.model;
import lombok.Data;
@Data
public class LoginMember {
private Long memberId;
private String token;
private Long loginTime;
private Long expireTime;
}

@ -107,6 +107,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
"/**/*.js",
"/profile/**"
).permitAll()
.antMatchers("/h5/**").permitAll()
.antMatchers("/no-auth/**").permitAll()
.antMatchers("/common/download**").anonymous()
.antMatchers("/common/download/resource**").anonymous()

@ -4,6 +4,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import com.ruoyi.common.core.domain.model.LoginMember;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@ -40,6 +42,10 @@ public class TokenService
@Value("${token.expireTime}")
private int expireTime;
//单位 天
@Value("${token.memberExpireTime}")
private int memberExpireTime;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
@ -76,6 +82,22 @@ public class TokenService
return null;
}
public LoginMember getLoginMember(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token)) {
try {
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_MEMBER_KEY);
String userKey = Constants.LOGIN_MEMBER_TOKEN_KEY + uuid;
return redisCache.getCacheObject(userKey);
} catch (Exception e) {
}
}
return null;
}
/**
*
*/
@ -117,6 +139,15 @@ public class TokenService
return createToken(claims);
}
public String createMemberToken(LoginMember loginMember){
String token = IdUtils.fastUUID();
loginMember.setToken(token);
refreshMemberToken(loginMember);
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_MEMBER_KEY, token);
return createToken(claims);
}
/**
* 20
*
@ -133,6 +164,14 @@ public class TokenService
}
}
public void verifyMemberToken(LoginMember loginUser) {
long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
refreshMemberToken(loginUser);
}
}
/**
*
*
@ -147,6 +186,14 @@ public class TokenService
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}
public void refreshMemberToken(LoginMember loginUser) {
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + memberExpireTime * 24 * 60 * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
String userKey = Constants.LOGIN_MEMBER_TOKEN_KEY + loginUser.getToken();
redisCache.setCacheObject(userKey, loginUser, memberExpireTime, TimeUnit.DAYS);
}
/**
*
*

@ -0,0 +1,17 @@
package com.cyl.h5.config;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cyl.ums.domain.Member;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.framework.config.LocalDataUtil;
import org.springframework.stereotype.Service;
@Service
public class SecurityUtil {
public static Member getLocalMember() {
Member member = (Member) LocalDataUtil.getVar(Constants.MEMBER_INFO);
return member;
}
}

@ -3,14 +3,16 @@ package com.cyl.h5.controller;
import com.cyl.h5.pojo.request.RegisterRequest;
import com.cyl.h5.pojo.response.RegisterResponse;
import com.cyl.h5.pojo.response.ValidatePhoneResponse;
import com.cyl.h5.pojo.response.H5LoginResponse;
import com.cyl.h5.service.H5MemberService;
import com.cyl.ums.pojo.vo.MemberVO;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/no-auth/h5/member")
@RequestMapping("/h5")
public class H5MemberController {
@Autowired
@ -27,4 +29,22 @@ public class H5MemberController {
public ResponseEntity<ValidatePhoneResponse> validate(@PathVariable String phone){
return ResponseEntity.ok(service.validate(phone));
}
@ApiOperation("手机号密码登录")
@PostMapping("/account/login")
public ResponseEntity<H5LoginResponse> accountLogin(@RequestBody String data){
return ResponseEntity.ok(service.accountLogin(data));
}
@ApiOperation("sms登录")
@PostMapping("/sms/login")
public ResponseEntity<H5LoginResponse> smsLogin(@RequestBody String data){
return ResponseEntity.ok(service.smsLogin(data));
}
@ApiOperation("获取会员信息")
@GetMapping("/member/info")
public ResponseEntity<MemberVO> getMemberInfo(){
return ResponseEntity.ok(service.getMemberInfo());
}
}

@ -0,0 +1,9 @@
package com.cyl.h5.pojo.request;
import lombok.Data;
@Data
public class H5AccountLoginRequest extends H5LoginRequest{
/** 密码 */
private String password;
}

@ -0,0 +1,9 @@
package com.cyl.h5.pojo.request;
import lombok.Data;
@Data
public class H5LoginRequest {
/** 账号即手机号 */
private String mobile;
}

@ -0,0 +1,11 @@
package com.cyl.h5.pojo.request;
import lombok.Data;
@Data
public class H5SmsLoginRequest extends H5LoginRequest {
/** 验证码 */
private String code;
/** uuid */
private String uuid;
}

@ -0,0 +1,13 @@
package com.cyl.h5.pojo.response;
import lombok.Data;
/**
* @Author: czc
* @Description: TODO
* @DateTime: 2023/6/16 14:54
**/
@Data
public class H5LoginResponse {
private String token;
}

@ -1,12 +1,9 @@
package com.cyl.h5.pojo.response;
import com.cyl.ums.domain.Member;
import lombok.Data;
@Data
public class RegisterResponse {
/** token */
private String token;
/** 会员信息 */
private Member member;
}

@ -1,18 +1,29 @@
package com.cyl.h5.service;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cyl.h5.pojo.request.H5AccountLoginRequest;
import com.cyl.h5.pojo.request.H5SmsLoginRequest;
import com.cyl.h5.pojo.request.RegisterRequest;
import com.cyl.h5.pojo.response.RegisterResponse;
import com.cyl.h5.pojo.response.ValidatePhoneResponse;
import com.cyl.h5.pojo.response.H5LoginResponse;
import com.cyl.ums.domain.Member;
import com.cyl.ums.mapper.MemberMapper;
import com.cyl.ums.pojo.vo.MemberVO;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginMember;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.LocalDataUtil;
import com.ruoyi.framework.web.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import java.time.LocalDateTime;
import java.util.Base64;
@ -27,6 +38,9 @@ public class H5MemberService {
@Autowired
private RedisCache redisCache;
@Autowired
private TokenService tokenService;
/**
*
* @param request
@ -34,25 +48,19 @@ public class H5MemberService {
*/
public RegisterResponse register(RegisterRequest request){
RegisterResponse response = new RegisterResponse();
//校验 验证码
String key = request.getUuid() + "_" + request.getMobile();
String code = redisCache.getCacheObject(key);
log.info("code:{}", code);
if (null == code){
throw new RuntimeException("验证码已过期");
}else if (!code.equals(request.getCode())){
throw new RuntimeException("验证码错误");
}
//删除缓存
redisCache.deleteObject(key);
//校验验证码
this.validateVerifyCode(request.getUuid(), request.getMobile(), request.getCode());
//创建会员
Member member = new Member();
member.setPhone(request.getMobile());
member.setPassword(SecurityUtils.encryptPassword(request.getPassword()));
member.setNickname("用户" + request.getMobile());
member.setNickname("用户" + request.getMobile().substring(7,11));
member.setStatus(Constants.MEMBER_ACCOUNT_STATUS.NORMAL);
member.setCreateTime(LocalDateTime.now());
memberMapper.insert(member);
//TODO 返回封装了token和member信息的response
//注册成功直接返回token了
H5LoginResponse loginResponse = getLoginResponse(member.getId());
response.setToken(loginResponse.getToken());
return response;
}
@ -70,4 +78,98 @@ public class H5MemberService {
response.setMessage("该手机号可用");
return response;
}
/**
*
* @param data
* @return
*/
public H5LoginResponse accountLogin(String data) {
if (StringUtils.isEmpty(data)){
throw new RuntimeException(Constants.LOGIN_INFO.WRONG);
}
// 解码 转 对象
H5AccountLoginRequest request = JSON.parseObject(new String(Base64Utils.decodeFromString(data)), H5AccountLoginRequest.class);
log.info("account login request:{}", JSONUtil.toJsonStr(request));
QueryWrapper<Member> qw = new QueryWrapper<>();
qw.eq("phone", request.getMobile());
Member member = memberMapper.selectOne(qw);
if (member == null){
throw new RuntimeException(Constants.LOGIN_INFO.WRONG);
}
validateMemberStatus(member);
//check 密码
if (!SecurityUtils.matchesPassword(request.getPassword(), member.getPassword())){
throw new RuntimeException(Constants.LOGIN_INFO.WRONG);
}
return getLoginResponse(member.getId());
}
public H5LoginResponse smsLogin(String data){
if (StringUtils.isEmpty(data)){
throw new RuntimeException(Constants.LOGIN_INFO.WRONG);
}
H5SmsLoginRequest request = JSON.parseObject(new String(Base64Utils.decodeFromString(data)), H5SmsLoginRequest.class);
//校验验证码
this.validateVerifyCode(request.getUuid(), request.getMobile(), request.getCode());
//查会员
QueryWrapper<Member> qw = new QueryWrapper<>();
qw.eq("phone", request.getMobile());
Member member = memberMapper.selectOne(qw);
if (member == null){
throw new RuntimeException(Constants.LOGIN_INFO.TO_REGISTER);
}
//校验会员状态
validateMemberStatus(member);
return getLoginResponse(member.getId());
}
/**
*
* @param member
*/
private void validateMemberStatus(Member member) {
if (Constants.MEMBER_ACCOUNT_STATUS.FORBIDDEN == member.getStatus()){
throw new RuntimeException(Constants.LOGIN_INFO.FORBIDDEN);
}
}
/**
*
* @param uuid
* @param phone
* @param inputCode
*/
private void validateVerifyCode(String uuid, String phone, String inputCode){
String key = uuid + "_" + phone;
String redisCode = redisCache.getCacheObject(key);
if (redisCode == null){
throw new RuntimeException(Constants.VERIFY_CODE_INFO.EXPIRED);
}else if (!redisCode.equals(inputCode)){
throw new RuntimeException(Constants.VERIFY_CODE_INFO.WRONG);
}
//删除缓存
redisCache.deleteObject(key);
}
/**
*
* @param memberId id
* @return
*/
private H5LoginResponse getLoginResponse(Long memberId){
LoginMember loginMember = new LoginMember();
loginMember.setMemberId(memberId);
String token = tokenService.createMemberToken(loginMember);
H5LoginResponse response = new H5LoginResponse();
response.setToken(token);
return response;
}
public MemberVO getMemberInfo() {
Member member = (Member) LocalDataUtil.getVar(Constants.MEMBER_INFO);
MemberVO memberVO = new MemberVO();
BeanUtils.copyProperties(member, memberVO);
return memberVO;
}
}

@ -19,9 +19,6 @@ public class MemberVO extends BaseAudit {
/** 昵称 */
@Excel(name = "昵称")
private String nickname;
/** 密码 */
@Excel(name = "密码")
private String password;
/** 手机号码 */
@Excel(name = "手机号码")
private String phone;

Loading…
Cancel
Save