diff --git a/db/schema.sql b/db/schema.sql index 45a44a5..61920d9 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -1,3 +1,19 @@ +drop table if exists `user` + +create table user +( + id int unsigned auto_increment + primary key, + create_time datetime null, + update_time datetime null, + username varchar(100) not null, + password varchar(255) not null, + nickname varchar(100) null +) + comment '用户表'; + + + drop table if exists `goal`; CREATE TABLE if not exists `goal` diff --git a/src/main/java/com/dota/nexus/controller/UserController.java b/src/main/java/com/dota/nexus/controller/UserController.java new file mode 100644 index 0000000..e0adfac --- /dev/null +++ b/src/main/java/com/dota/nexus/controller/UserController.java @@ -0,0 +1,28 @@ +package com.dota.nexus.controller; + +import com.dota.nexus.entity.LoginDTO; +import com.dota.nexus.entity.R; +import com.dota.nexus.service.UserService; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("user") +public class UserController { + UserService userService; + + public UserController(UserService userService) { + this.userService = userService; + } + + @PostMapping("login") + public R login(LoginDTO loginDTO) throws Exception { + var res = userService.login(loginDTO.username(), loginDTO.password()); + if (res==null) { + return R.error("用户不存在或者密码错误"); + } + + return R.ok(res); + } +} diff --git a/src/main/java/com/dota/nexus/entity/LoginDTO.java b/src/main/java/com/dota/nexus/entity/LoginDTO.java new file mode 100644 index 0000000..38aa35b --- /dev/null +++ b/src/main/java/com/dota/nexus/entity/LoginDTO.java @@ -0,0 +1,4 @@ +package com.dota.nexus.entity; + +public record LoginDTO(String username, String password) { +} diff --git a/src/main/java/com/dota/nexus/entity/R.java b/src/main/java/com/dota/nexus/entity/R.java index 1771b85..08f7b2d 100644 --- a/src/main/java/com/dota/nexus/entity/R.java +++ b/src/main/java/com/dota/nexus/entity/R.java @@ -27,8 +27,12 @@ public class R { return new R(200, "ok", data); } + public static R error(String msg){ + return new R(500, msg); + } + public static R error(){ - return new R(500, "服务端发生未知错误"); + return error("服务端发生未知错误"); } public static R unauthorized() { diff --git a/src/main/java/com/dota/nexus/entity/User.java b/src/main/java/com/dota/nexus/entity/User.java new file mode 100644 index 0000000..d58c816 --- /dev/null +++ b/src/main/java/com/dota/nexus/entity/User.java @@ -0,0 +1,14 @@ +package com.dota.nexus.entity; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class User extends Entity{ + private String name; + + private String password; + + private String nickname; +} diff --git a/src/main/java/com/dota/nexus/mapper/UserMapper.java b/src/main/java/com/dota/nexus/mapper/UserMapper.java new file mode 100644 index 0000000..2453e75 --- /dev/null +++ b/src/main/java/com/dota/nexus/mapper/UserMapper.java @@ -0,0 +1,9 @@ +package com.dota.nexus.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.dota.nexus.entity.User; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface UserMapper extends BaseMapper { +} diff --git a/src/main/java/com/dota/nexus/service/UserService.java b/src/main/java/com/dota/nexus/service/UserService.java new file mode 100644 index 0000000..e0d7507 --- /dev/null +++ b/src/main/java/com/dota/nexus/service/UserService.java @@ -0,0 +1,9 @@ +package com.dota.nexus.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.dota.nexus.entity.User; + +public interface UserService extends IService { + + String login(String username, String password) throws Exception; +} diff --git a/src/main/java/com/dota/nexus/service/impl/UserServiceImpl.java b/src/main/java/com/dota/nexus/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..0d6e149 --- /dev/null +++ b/src/main/java/com/dota/nexus/service/impl/UserServiceImpl.java @@ -0,0 +1,27 @@ +package com.dota.nexus.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.dota.nexus.entity.User; +import com.dota.nexus.mapper.UserMapper; +import com.dota.nexus.service.UserService; +import com.dota.nexus.util.GlobalMap; +import com.dota.nexus.util.PasswordUtil; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +@Service +public class UserServiceImpl extends ServiceImpl implements UserService { + public String login(String username, String password) throws Exception { + var q = new LambdaQueryWrapper(); + q.eq(User::getName, username); + var u = this.baseMapper.selectOne(q); + if (u!=null && PasswordUtil.verify(password, u.getPassword())) { + var uuid = UUID.randomUUID().toString(); + GlobalMap.put(uuid, u.getId()); + return uuid; + } + return null; + } +} diff --git a/src/main/java/com/dota/nexus/util/GlobalMap.java b/src/main/java/com/dota/nexus/util/GlobalMap.java new file mode 100644 index 0000000..bb191eb --- /dev/null +++ b/src/main/java/com/dota/nexus/util/GlobalMap.java @@ -0,0 +1,16 @@ +package com.dota.nexus.util; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class GlobalMap { + private static final Map MAP = new ConcurrentHashMap<>(); + + public static void put(String k, Object v) { + MAP.put(k,v); + } + + public static Object get(String k) { + MAP.get(k); + } +} diff --git a/src/main/java/com/dota/nexus/util/PasswordUtil.java b/src/main/java/com/dota/nexus/util/PasswordUtil.java new file mode 100644 index 0000000..627235e --- /dev/null +++ b/src/main/java/com/dota/nexus/util/PasswordUtil.java @@ -0,0 +1,47 @@ +package com.dota.nexus.util; + +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import java.security.SecureRandom; +import java.util.Base64; + +public class PasswordUtil { + public static String encrypt(String password) throws Exception{ + var random = new SecureRandom(); + var salt = new byte[16]; + random.nextBytes(salt); + + var spec = new PBEKeySpec( + password.toCharArray(), + salt, + 100000, + 256 + ); + var factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + var hash = factory.generateSecret(spec).getEncoded(); + return Base64.getEncoder().encodeToString(salt) + ":" + Base64.getEncoder().encodeToString(hash); + } + + public static boolean verify(String password, String storedHash) throws Exception { + var parts = storedHash.split(":"); + var salt = Base64.getDecoder().decode(parts[0]); + PBEKeySpec spec = new PBEKeySpec( + password.toCharArray(), + salt, + 100000, + 256 + ); + byte[] testHash = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256") + .generateSecret(spec).getEncoded(); + + return parts[1].equals(Base64.getEncoder().encodeToString(testHash)); + } + + public static void main(String[] args) throws Exception{ + var s = "nexus2017"; + var pass =encrypt(s); + System.out.println(pass); + System.out.println(pass.length()); + System.out.println(verify(s, pass)); + } +} diff --git a/src/main/java/com/dota/nexus/util/TokenUtil.java b/src/main/java/com/dota/nexus/util/TokenUtil.java new file mode 100644 index 0000000..547e41a --- /dev/null +++ b/src/main/java/com/dota/nexus/util/TokenUtil.java @@ -0,0 +1,13 @@ +package com.dota.nexus.util; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +public class TokenUtil { + public static Integer CurrentUserId() { + var req = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest(); + String authorization = req.getHeader("Authorization"); + var token = authorization.replace("Bearer ", ""); + return (Integer) GlobalMap.get(token); + } +}