完成小红书登陆注册

This commit is contained in:
wangxulei 2024-12-23 17:28:28 +08:00
parent 9444e03451
commit c8796352a4
13 changed files with 231 additions and 98 deletions

View File

@ -1,14 +1,10 @@
package com.dd.admin.business.api;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dd.admin.business.note.domain.NoteDto;
import com.dd.admin.business.note.domain.NoteVo;
import com.dd.admin.business.author.entity.Author;
import com.dd.admin.business.author.service.AuthorService;
import com.dd.admin.common.aop.operationLog.aop.OperLog;
import com.dd.admin.common.aop.operationLog.aop.OperType;
import com.dd.admin.common.exception.ApiException;
import com.dd.admin.common.model.result.ResultBean;
import com.dd.admin.common.utils.RedisUtil;
import com.dd.admin.common.utils.StringUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
@ -17,41 +13,14 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class AuthApi {
@Autowired
RedisUtil redisUtil;
AuthorService authorService;
@ApiOperation(value = "获取验证码")
@ApiOperation(value = "获取博主信息")
@ApiOperationSupport(order = 1)
@GetMapping("/api/auth/getCode")
@OperLog(operModule = "获取验证码",operType = OperType.QUERY,operDesc = "获取验证码")
public ResultBean<String> page(String phoneNumber) {
String code = sendSmsCode(phoneNumber);
return ResultBean.success(code);
@GetMapping("/api/auth/getMine")
@OperLog(operModule = "获取博主信息",operType = OperType.QUERY,operDesc = "获取博主信息")
public ResultBean<Author> getMine() {
return ResultBean.success();
}
public String sendSmsCode(String phoneNumber) {
String redisKey = "SMS_CODE" + phoneNumber;
String smsCode = String.valueOf(redisUtil.get(redisKey));
if(StringUtil.isNotEmpty(smsCode)){
throw new ApiException("验证码已发送,请稍后再试" + smsCode);
}
String code = StringUtil.createCode(4);
//设置有效时间
// String json = JavaSmsApi.tplSingleSend(phoneNumber,CODE_TPL_ID, BeanUtil.beanToMap(new SmsCode(code)));
// Map dataMap = (Map) JSON.parse(json);
// if(dataMap.get("msg").equals("发送成功")){
if(true){
System.out.println(code);
redisUtil.set(redisKey,code,120);
return code;
}else{
throw new ApiException("发送失败");
// throw new ApiException("发送失败,"+dataMap.get("msg"));
}
}
}

View File

@ -0,0 +1,68 @@
package com.dd.admin.business.api;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dd.admin.business.api.domain.PhoneLoginDto;
import com.dd.admin.business.api.service.LoginService;
import com.dd.admin.business.author.entity.Author;
import com.dd.admin.business.author.service.AuthorService;
import com.dd.admin.business.note.domain.NoteDto;
import com.dd.admin.business.note.domain.NoteVo;
import com.dd.admin.common.aop.operationLog.aop.OperLog;
import com.dd.admin.common.aop.operationLog.aop.OperType;
import com.dd.admin.common.exception.ApiException;
import com.dd.admin.common.model.result.ResultBean;
import com.dd.admin.common.security.jwt.JwtTokenUtil;
import com.dd.admin.common.utils.RedisUtil;
import com.dd.admin.common.utils.StringUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
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;
@RestController
public class LoginApi {
@Autowired
LoginService loginService;
@Autowired
AuthorService authorService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@ApiOperation(value = "获取验证码")
@ApiOperationSupport(order = 1)
@GetMapping("/api/getCode")
@OperLog(operModule = "获取验证码",operType = OperType.QUERY,operDesc = "获取验证码")
public ResultBean<String> getCode(String phoneNumber) {
String code = loginService.sendSmsCode(phoneNumber);
return ResultBean.success(code);
}
@ApiOperation(value = "验证码登陆")
@ApiOperationSupport(order = 1)
@PostMapping("/api/checkCode")
@Transactional
@OperLog(operModule = "获取验证码",operType = OperType.OTHER,operDesc = "验证码登陆")
public ResultBean<Author> checkCode(@RequestBody PhoneLoginDto phoneLoginDto) {
loginService.checkCode(phoneLoginDto);
//验证后登陆
Author author = authorService.selectAuthorByPhoneNumber(phoneLoginDto.getPhoneNumber());
if(author==null){
author = authorService.createNewAuthor(phoneLoginDto.getPhoneNumber());
}
//根据用户id生成token
final String token = jwtTokenUtil.generateTokenByUserId(author.getAuthorId());
author.setToken(token);
return ResultBean.success(author);
}
}

View File

@ -0,0 +1,13 @@
package com.dd.admin.business.api.domain;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class PhoneLoginDto {
@NotBlank(message = "手机号不能为空")
private String phoneNumber;
@NotBlank(message = "验证码不能为空")
private String code;
}

View File

@ -0,0 +1,9 @@
package com.dd.admin.business.api.service;
import com.dd.admin.business.api.domain.PhoneLoginDto;
public interface LoginService {
public String sendSmsCode(String phoneNumber);
public void checkCode(PhoneLoginDto phoneLoginDto);
}

View File

@ -0,0 +1,52 @@
package com.dd.admin.business.api.service.impl;
import com.dd.admin.business.api.domain.PhoneLoginDto;
import com.dd.admin.business.api.service.LoginService;
import com.dd.admin.business.author.entity.Author;
import com.dd.admin.common.exception.ApiException;
import com.dd.admin.common.utils.RedisUtil;
import com.dd.admin.common.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
RedisUtil redisUtil;
@Override
public String sendSmsCode(String phoneNumber) {
String redisKey = "SMS_CODE" + phoneNumber;
String smsCode = String.valueOf(redisUtil.get(redisKey));
if (StringUtil.isNotEmpty(smsCode)) {
throw new ApiException("验证码已发送,请稍后再试" + smsCode);
}
String code = StringUtil.createCode(4);
//设置有效时间
// String json = JavaSmsApi.tplSingleSend(phoneNumber,CODE_TPL_ID, BeanUtil.beanToMap(new SmsCode(code)));
// Map dataMap = (Map) JSON.parse(json);
// if(dataMap.get("msg").equals("发送成功")){
if (true) {
System.out.println(code);
redisUtil.set(redisKey, code, 120);
return code;
} else {
throw new ApiException("发送失败");
// throw new ApiException("发送失败,"+dataMap.get("msg"));
}
}
@Override
public void checkCode(PhoneLoginDto phoneLogin) {
String code = phoneLogin.getCode();
String phoneNumber = phoneLogin.getPhoneNumber();
String smsCode = String.valueOf(redisUtil.get("SMS_CODE" + phoneNumber));
//验证验证码是否正确
if(!code.matches(smsCode)){
throw new ApiException("验证码有误");
}
}
}

View File

@ -140,5 +140,6 @@ public class Author implements Serializable {
@TableField("PHONE_NUMBER")
private String phoneNumber;
@TableField(exist = false)
private String token;
}

View File

@ -23,4 +23,8 @@ public interface AuthorService extends IService<Author> {
//作者博主-列表
List<AuthorVo> selectAuthorList(AuthorDto authorDto);
Author selectAuthorByPhoneNumber(String phoneNumber);
Author createNewAuthor(String phoneNumber);
}

View File

@ -1,5 +1,6 @@
package com.dd.admin.business.author.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dd.admin.common.model.PageFactory;
@ -7,9 +8,16 @@ import com.dd.admin.business.author.entity.Author;
import com.dd.admin.business.author.mapper.AuthorMapper;
import com.dd.admin.business.author.service.AuthorService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.admin.common.utils.AddressUtils;
import com.dd.admin.common.utils.IPUtils;
import com.dd.admin.common.utils.RandomXiaohongshuAuthorName;
import com.dd.admin.common.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dd.admin.business.author.domain.AuthorVo;
import com.dd.admin.business.author.domain.AuthorDto;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
@ -23,6 +31,9 @@ import java.util.List;
@Service
public class AuthorServiceImpl extends ServiceImpl<AuthorMapper, Author> implements AuthorService {
@Autowired
HttpServletRequest request;
@Override
public IPage<AuthorVo> selectAuthorPage(AuthorDto authorDto) {
Page page = PageFactory.defaultPage();
@ -33,4 +44,29 @@ public class AuthorServiceImpl extends ServiceImpl<AuthorMapper, Author> impleme
public List<AuthorVo> selectAuthorList(AuthorDto authorDto) {
return baseMapper.selectAuthorList(authorDto);
}
@Override
public Author selectAuthorByPhoneNumber(String phoneNumber) {
LambdaQueryWrapper<Author> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Author::getPhoneNumber,phoneNumber);
Author author = baseMapper.selectOne(queryWrapper);
return author;
}
@Override
public Author createNewAuthor(String phoneNumber) {
Author author = new Author();
author.setPhoneNumber(phoneNumber);
//随机生成昵称
author.setAuthorName(RandomXiaohongshuAuthorName.generateAuthorName());
author.setAuthorNo(StringUtil.getDateStringNow() + StringUtil.createCode(4));
author.setDescription("我是" + author.getAuthorName());
//生成随机头像因为没有点击上传所有没有头像id
author.setAvatarUrl("http://8.146.211.120:8080/upload/avatar/avatar ("+ StringUtil.createCode(1) +").jpg");
author.setBackGroundUrl("http://8.146.211.120:8080/upload/notes/note (6).jpg");
author.setIpAddress(IPUtils.getIpAddr(request)); // 请求IP
author.setIpRealAddress(AddressUtils.getRealAddress(author.getIpAddress())); //ip真实地址
this.save(author);
return author;
}
}

View File

@ -1,5 +1,6 @@
package com.dd.admin.common.config;
import com.dd.admin.common.security.interceptor.ApiInterceptor;
import com.dd.admin.common.utils.ToolUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
@ -9,6 +10,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -24,7 +26,7 @@ import java.util.List;
* @date 2021/7/6
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
public class GolbalConfig implements WebMvcConfigurer {
@Value("${dd.uploadPath}")
@ -59,6 +61,12 @@ public class CorsConfig implements WebMvcConfigurer {
}
// 注册拦截器的方法
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ApiInterceptor())
.addPathPatterns("/api/auth/**"); // 拦截/api下所有请求路径
}
// @Bean

View File

@ -1,62 +1,32 @@
package com.dd.admin.common.security.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.hutool.core.util.StrUtil;
import com.dd.admin.common.exception.ApiException;
import com.dd.admin.common.security.jwt.service.JwtUserDetailsService;
import com.dd.admin.common.utils.RedisUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.swagger.annotations.Api;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class ApiInterceptor implements HandlerInterceptor {
private final JwtUserDetailsService jwtUserDetailsService;
public ApiInterceptor(JwtUserDetailsService jwtUserDetailsService) {
this.jwtUserDetailsService = jwtUserDetailsService;
}
@Override
public boolean preIntercept(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取请求路径判断是否是以/api开头
String requestUri = request.getRequestURI();
if (requestUri.startsWith("/api")) {
// 在这里编写验证手机号和验证码的逻辑比如从请求参数或者请求头中获取相关信息进行验证
// 假设从请求参数中获取手机号和验证码示例代码如下实际情况可能需要根据具体业务从合适的地方获取
String phone = request.getParameter("phone");
String verificationCode = request.getParameter("verificationCode");
if (isPhoneValid(phone) && isVerificationCodeValid(verificationCode)) {
// 根据验证通过的手机号等信息获取对应的用户详情这里假设你的用户详情是通过JwtUserDetailsService来获取实际可能需要根据具体业务调整
UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(phone);
// 创建认证对象将用户详情放入其中这里假设认证方式是基于用户名密码形式可根据实际调整
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
// 将认证对象放入SecurityContextHolder中模拟用户已认证的状态
SecurityContextHolder.getContext().setAuthentication(authentication);
return true; // 验证通过放行请求
} else {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 设置未授权状态码
return false; // 验证不通过拦截请求
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (StrUtil.isBlank(token)) {
throw new ApiException("请登录后访问");
}
return true; // 如果不是/api开头的请求直接放行
}
private boolean isPhoneValid(String phone) {
// 这里编写手机号验证的具体逻辑比如正则表达式验证手机号格式是否正确等
return true; // 示例先返回true实际需完善逻辑
return true;
}
private boolean isVerificationCodeValid(String verificationCode) {
// 这里编写验证码验证的具体逻辑比如和后台存储的验证码进行比对等
return true; // 示例先返回true实际需完善逻辑
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
}

View File

@ -57,6 +57,11 @@ public class JwtTokenUtil implements Serializable {
return doGenerateToken(claims, filterKey + userDetails.getUsername());
}
public String generateTokenByUserId(String userId) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userId);
}
//while creating the token -
//1. Define claims of the token, like Issuer, Expiration, Subject, and the ID
//2. Sign the JWT using the HS512 algorithm and secret key.

View File

@ -87,10 +87,4 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
// 注册拦截器的方法
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ApiInterceptor())
.addPathPatterns("/api/**"); // 拦截/api下所有请求路径
}
}

View File

@ -3,9 +3,13 @@ package com.dd.admin.common.utils;
import java.util.Random;
public class RandomXiaohongshuAuthorName {
// 增加更多风格各异的形容词
private static final String[] ADJECTIVES = {"甜系", "酷盖", "元气", "文艺", "清新", "时尚", "复古", "个性", "慵懒", "灵动","甜系", "萌趣", "清新", "元气", "梦幻", "文艺", "优雅", "酷盖", "潮流", "时尚", "复古", "治愈", "俏皮", "灵动", "简约", "精致", "浪漫", "神秘", "个性", "森系"};
// 丰富名词列表
private static final String[] NOUNS = {"喵星人", "星辰", "云朵", "花田", "森林", "梦境", "清风", "暖阳", "微光", "小确幸","小熊", "兔子", "云朵", "星辰", "花朵", "森林", "海风", "咖啡", "画笔", "月光", "糖果", "蛋糕", "风铃", "泡泡", "琉璃", "蝴蝶"};
// 定义一些风格词汇数组
private static final String[] ADJECTIVES = {"甜系", "酷盖", "元气", "文艺", "清新", "时尚", "复古", "个性", "慵懒", "灵动"};
private static final String[] NOUNS = {"喵星人", "星辰", "云朵", "花田", "森林", "梦境", "清风", "暖阳", "微光", "小确幸"};
public static void main(String[] args) {
String authorName = generateAuthorName();
@ -25,4 +29,4 @@ public class RandomXiaohongshuAuthorName {
return adjective + noun + number;
}
}
}