Просмотр исходного кода

Merge remote-tracking branch 'origin/yzz' into text

# Conflicts:
#	src/main/java/com/futu/course/user/controller/UserController.java
#	src/main/java/com/futu/course/user/service/UserService.java
#	src/main/java/com/futu/course/user/service/impl/UserServiceImpl.java
lzy 2 недель назад
Родитель
Сommit
46f56001f6

+ 5 - 0
pom.xml

@@ -30,6 +30,11 @@
             <version>1.2.80</version>
         </dependency>
         <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>3.12.1</version>
+        </dependency>
+        <dependency>
             <groupId>io.jsonwebtoken</groupId>
             <artifactId>jjwt-api</artifactId>
             <version>0.11.5</version>

+ 43 - 0
src/main/java/com/futu/course/common/config/RedissonConfig.java

@@ -0,0 +1,43 @@
+package com.futu.course.common.config;
+
+import org.apache.commons.lang3.StringUtils;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfig {
+
+  @Value("${spring.redis.host}")
+   private String host;
+    @Value("${spring.redis.port}")
+    private int port;
+    @Value("${spring.redis.database}")
+    private int database;
+    @Value("${spring.redis.password}")
+    private String password;
+
+
+        @Bean
+        public RedissonClient getRedisson() {
+            Config config = new Config();
+            config.useSingleServer().setAddress("redis://" + host + ":" + port)
+                    .setDatabase(database);
+            if (StringUtils.isNotEmpty(password)) {
+                config.useSingleServer().setAddress("redis://" + host + ":" + port).setDatabase(database)
+                        .setPassword(password);
+            } else {
+                config.useSingleServer().setAddress("redis://" + host + ":" + port).setDatabase(database);
+            }
+            //设置全局默认看门狗机续期时间,如果在使用时不设置,则使用全局的,如果全局不设置,则使用默认的30000,单位毫秒
+            config.setLockWatchdogTimeout(2000);
+            return Redisson.create(config);
+        }
+    }
+
+
+
+

+ 17 - 0
src/main/java/com/futu/course/user/controller/UserController.java

@@ -1,6 +1,7 @@
 package com.futu.course.user.controller;
 
 
+
 import com.futu.course.user.service.impl.UserServiceImpl;
 import io.minio.errors.*;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -15,6 +16,11 @@ import java.security.NoSuchAlgorithmException;
 import com.futu.course.common.annotation.NonLoginRequired;
 import com.futu.course.common.entity.R;
 import com.futu.course.user.dto.UserDTO;
+import com.futu.course.common.annotation.NonLoginRequired;
+import com.futu.course.common.entity.R;
+import com.futu.course.user.dto.UserDTO;
+import com.futu.course.user.dto.UserLoginDto;
+import com.futu.course.user.dto.UserRegisterDto;
 import com.futu.course.user.service.UserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -22,6 +28,7 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+
 /**
  * @author "杨旭朋"
  * @ClassName: UserController
@@ -37,6 +44,7 @@ public class UserController {
         return userService.unload(multipartFile, uid);
     }
 
+
     @NonLoginRequired
     @PostMapping("wx_login")
     public R wxLogin(@RequestBody UserDTO dto) {
@@ -49,4 +57,13 @@ public class UserController {
         System.out.println(dto);
         return userService.logout(dto);
     }
+
+    //手机号密码登录
+    @NonLoginRequired
+    @PostMapping("login")
+    public R login(@RequestBody UserLoginDto dto) throws InterruptedException {
+        return userService.login(dto);
+    }
+
+
 }

+ 14 - 0
src/main/java/com/futu/course/user/dto/UserLoginDto.java

@@ -0,0 +1,14 @@
+package com.futu.course.user.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class UserLoginDto {
+    @NotBlank(message = "手机号不能为空")
+    private String mobile;
+    @NotBlank(message = "密码不能为空")
+    private String password;
+
+}

+ 11 - 0
src/main/java/com/futu/course/user/dto/UserRegisterDto.java

@@ -0,0 +1,11 @@
+package com.futu.course.user.dto;
+
+import lombok.Data;
+
+@Data
+public class UserRegisterDto {
+    private String username;
+    private String password;
+    private String nickname;
+    private String  mobile;
+}

+ 6 - 2
src/main/java/com/futu/course/user/service/UserService.java

@@ -1,8 +1,10 @@
 package com.futu.course.user.service;
 
-
 import com.futu.course.user.domain.User;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.futu.course.user.dto.UserDTO;
+import com.futu.course.user.dto.UserLoginDto;
+import com.futu.course.user.dto.UserRegisterDto;
 
 import com.futu.course.common.entity.R;
 import com.futu.course.user.domain.User;
@@ -13,7 +15,6 @@ import com.futu.course.user.dto.UserDTO;
 /**
 * @author yuu
 * @description 针对表【user(用户表)】的数据库操作Service
-<<<<<<< HEAD
 * @createDate 2025-05-05 18:52:53
 */
 public interface UserService extends IService<User> {
@@ -22,4 +23,7 @@ public interface UserService extends IService<User> {
 
     R logout(UserDTO dto);
 
+    R login(UserLoginDto dto) throws InterruptedException;
+
+
 }

+ 132 - 18
src/main/java/com/futu/course/user/service/impl/UserServiceImpl.java

@@ -1,6 +1,9 @@
 package com.futu.course.user.service.impl;
 
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.futu.course.minio.service.impl.FileServiceImpl;
 import com.futu.course.user.domain.User;
@@ -16,9 +19,16 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.futu.course.common.entity.R;
 import com.futu.course.common.utils.SnowflakeIdWorker;
 import com.futu.course.common.utils.TokenUtils;
+import com.futu.course.common.entity.R;
+import com.futu.course.common.utils.SnowflakeIdWorker;
+import com.futu.course.common.utils.TokenUtils;
 import com.futu.course.user.domain.User;
 import com.futu.course.user.dto.LoginDTO;
 import com.futu.course.user.dto.UserDTO;
+import com.futu.course.user.dto.LoginDTO;
+import com.futu.course.user.dto.UserDTO;
+import com.futu.course.user.dto.UserLoginDto;
+import com.futu.course.user.dto.UserRegisterDto;
 import com.futu.course.user.service.UserService;
 import com.futu.course.user.mapper.UserMapper;
 import io.jsonwebtoken.Jwts;
@@ -35,6 +45,23 @@ import org.apache.http.util.EntityUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.StringRedisTemplate;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
+import io.lettuce.core.RedisClient;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.multipart.MultipartFile;
@@ -51,21 +78,27 @@ import java.security.NoSuchAlgorithmException;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+import org.springframework.util.DigestUtils;
+
+import javax.annotation.Resource;
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
 * @author yuu
 * @description 针对表【user(用户表)】的数据库操作Service实现
 * @createDate 2025-05-05 18:52:53
-=======
-/**
-* @author yuu
-* @description 针对表【user(用户表)】的数据库操作Service实现
-* @createDate 2025-05-07 08:26:30
->>>>>>> bba2fa3 ("微信一键登录实现")
 */
 @Service
 public class UserServiceImpl extends ServiceImpl<UserMapper, User>
-    implements UserService {
+    implements UserService{
+
 
     @Autowired
     private UserMapper userMapper;
@@ -73,6 +106,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
     @Autowired
     private RedisTemplate redisTemplate;
 
+    @Autowired
+    private RedissonClient redissonClient;
 
     @Autowired
     private FileServiceImpl fileService;
@@ -84,19 +119,21 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
         return b?"修改成功":"修改失败";
     }
 
+
+
+
     // 填写上你的AppID,如何获取AppID自行百度,这步骤很简单
     private final static String APP_ID = "wxdbcbc020c8e4b0d9";
     // 填写上你的AppSecret,如何获取AppSecret自行百度,这步骤很简单
     private final static String APP_SECRET = "60efa9e4ff7fae35c7f561de7763da7a";
     // 微信小程序登录校验请求地址
     private final static String LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
-
     @Override
     public R appLogin(UserDTO dto) {
 
-        SnowflakeIdWorker worker = new SnowflakeIdWorker(1, 1);
+        SnowflakeIdWorker worker=new SnowflakeIdWorker(1,1);
         System.out.println(dto);
-        String url = LOGIN_URL + "?appid=" + APP_ID + "&secret=" + APP_SECRET + "&grant_type=authorization_code&js_code=" + dto.getCode();
+        String url = LOGIN_URL + "?appid=" + APP_ID + "&secret="+ APP_SECRET + "&grant_type=authorization_code&js_code=" + dto.getCode();
         HttpClient client = HttpClients.createDefault(); // 创建默认http连接
         HttpGet getRequest = new HttpGet(url);// 创建一个post请求
         LoginDTO loginDTO = new LoginDTO();
@@ -108,13 +145,13 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
             // 把响应实体转成文本
             String html = EntityUtils.toString(entity);
             loginDTO = JSON.parseObject(html, LoginDTO.class);
-            if (null == loginDTO.getErrCode()) {
+            if(null == loginDTO.getErrCode()) {
                 dto.setWxId(loginDTO.getOpenid());
             } else {
-                return R.restResult(loginDTO, loginDTO.getErrCode(), loginDTO.getErrMsg());
+                return R.restResult(loginDTO,loginDTO.getErrCode(),loginDTO.getErrMsg());
             }
             List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getOpenId, dto.getWxId()));
-            if (users.size() > 0) {
+            if(users.size() > 0) {
                 User user = users.get(0);
                 // 生成一个 256 位(32 字节)的安全密钥
                 SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
@@ -124,9 +161,10 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
                         .signWith(key)
                         .compact();
                 user.setToken(jws);
-                redisTemplate.opsForValue().set("user", user, 1, TimeUnit.DAYS);
+                redisTemplate.opsForValue().set("user",user,1, TimeUnit.DAYS);
                 return R.ok(user);
-            } else {
+            }
+            else {
                 User user = new User();
                 String sessionKey = loginDTO.getSession_key();
 
@@ -158,7 +196,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
                         .compact();
                 user.setToken(jws);
                 userMapper.insert(user);
-                redisTemplate.opsForValue().set("user", user, 1, TimeUnit.DAYS);
+                redisTemplate.opsForValue().set("user",user,1, TimeUnit.DAYS);
                 return R.ok(user);
             }
         } catch (ClientProtocolException e) {
@@ -171,12 +209,72 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
 
     @Override
     public R logout(UserDTO dto) {
-        if (redisTemplate.opsForValue().get("user") != null) {
+        if (redisTemplate.opsForValue().get("user") != null)
+        {
             redisTemplate.delete("user");
         }
         return R.ok("登出成功");
     }
 
+    @Override
+    public R login(UserLoginDto dto) throws InterruptedException {
+        RLock lock = redissonClient.getLock(dto.getMobile());
+        boolean b = lock.tryLock(3, TimeUnit.SECONDS);
+        if (!b)
+        {
+            return R.failed("请勿重复提交");
+        }
+        try {
+            User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getMobile, dto.getMobile()));
+            if (user == null)
+            {
+                return R.restResult(null,500,"用户不存在");
+            }
+            String salt = user.getSalt();
+            String password = dto.getPassword();
+            String hex = DigestUtils.md5DigestAsHex((salt + password).getBytes());
+            if (hex.equals(user.getPassword()))
+            {
+                // 生成一个 256 位(32 字节)的安全密钥
+                SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
+                // 使用密钥生成 JWT
+                String jws = Jwts.builder()
+                        .setSubject(user.getId().toString())
+                        .signWith(key)
+                        .compact();
+                user.setToken(jws);
+                redisTemplate.opsForValue().set("user",user,1, TimeUnit.DAYS);
+                return R.ok(user);
+            }
+
+        }catch (Exception e)
+        {
+            e.printStackTrace();
+            throw e;
+        }finally {
+            if (lock.isLocked()&&lock.isHeldByCurrentThread())
+            {
+                lock.unlock();
+            }
+        }
+        return null;
+    }
+
+//    @Override
+//    public R register(UserRegisterDto dto) {
+//        SnowflakeIdWorker worker=new SnowflakeIdWorker(1,1);
+//        if (redisTemplate.opsForValue().get("user") != null)
+//        {
+//            return R.failed("用户已存在");
+//        }
+//        try {
+//            User user = new User();
+//            user.setId(worker.nextId());
+//        }
+//
+//        return null;
+//    }
+
 
     public static String decryptData(String encryptedData, String sessionKey, String iv) throws Exception {
         // Base64 解码
@@ -194,9 +292,25 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User>
         byte[] decryptedBytes = cipher.doFinal(encryptedDataBytes);
         return new String(decryptedBytes, StandardCharsets.UTF_8);
     }
-}
 
 
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+
+
+