diff --git a/pom.xml b/pom.xml index 4054cdb..3fa34ad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.3.1 + 2.7.16 com.example @@ -34,12 +34,25 @@ org.springframework.boot spring-boot-starter - + + com.auth0 + java-jwt + 3.8.3 + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.3.0 + org.springframework.boot spring-boot-starter-test test + + org.projectlombok + lombok + com.alibaba @@ -51,6 +64,15 @@ httpclient 4.5.6 + + mysql + mysql-connector-java + 8.0.33 + + + org.springframework.boot + spring-boot-starter-data-redis + org.springframework.boot spring-boot-starter-web diff --git a/src/main/java/com/example/aitest/controller/ApiController.java b/src/main/java/com/example/aitest/controller/ApiController.java index 21cf1ed..ffe7f59 100644 --- a/src/main/java/com/example/aitest/controller/ApiController.java +++ b/src/main/java/com/example/aitest/controller/ApiController.java @@ -1,24 +1,14 @@ package com.example.aitest.controller; -import com.alibaba.fastjson.JSON; + import com.alibaba.fastjson.JSONObject; import com.example.aitest.dto.ApiDto; import com.example.aitest.service.ApiService; -import jakarta.annotation.Resource; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; - -import java.io.File; -import java.io.FileOutputStream; +import javax.annotation.Resource; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/main/java/com/example/aitest/controller/UserController.java b/src/main/java/com/example/aitest/controller/UserController.java new file mode 100644 index 0000000..4a2f6c3 --- /dev/null +++ b/src/main/java/com/example/aitest/controller/UserController.java @@ -0,0 +1,28 @@ +package com.example.aitest.controller; + +import com.example.aitest.pojo.User; +import com.example.aitest.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.security.NoSuchAlgorithmException; + +@RestController +public class UserController { + + @Autowired + public UserService userService; + @PostMapping("/login") + public String login(@RequestBody User user) throws NoSuchAlgorithmException { + return userService.login(user); + } + + @PostMapping("/register") + public String register(@RequestBody User user) throws NoSuchAlgorithmException { + return userService.register(user); + } + +} diff --git a/src/main/java/com/example/aitest/dao/redis/CodeRedis.java b/src/main/java/com/example/aitest/dao/redis/CodeRedis.java new file mode 100644 index 0000000..0b0331f --- /dev/null +++ b/src/main/java/com/example/aitest/dao/redis/CodeRedis.java @@ -0,0 +1,32 @@ +package com.example.aitest.dao.redis; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +@Repository +public class CodeRedis implements RedisUtil { + @Resource + StringRedisTemplate stringRedisTemplate; + + @Override + public void addRedis(String account, String code) { + if (account != null && code != null) { + ValueOperations valueOperations = stringRedisTemplate.opsForValue(); + valueOperations.set(account, code, 60, TimeUnit.SECONDS); + } + } + + @Override + public String getRedis(String account) { + return stringRedisTemplate.opsForValue().get(account); + } + + @Override + public void delRedis(String account) { + + } +} diff --git a/src/main/java/com/example/aitest/dao/redis/RedisUtil.java b/src/main/java/com/example/aitest/dao/redis/RedisUtil.java new file mode 100644 index 0000000..3897e52 --- /dev/null +++ b/src/main/java/com/example/aitest/dao/redis/RedisUtil.java @@ -0,0 +1,13 @@ +package com.example.aitest.dao.redis; + +import org.springframework.stereotype.Repository; + +@Repository +public interface RedisUtil { + public abstract void addRedis(String key, String value); + + public abstract void delRedis(String key); + + public abstract String getRedis(String key); + +} diff --git a/src/main/java/com/example/aitest/dao/redis/TokenRedis.java b/src/main/java/com/example/aitest/dao/redis/TokenRedis.java new file mode 100644 index 0000000..5718297 --- /dev/null +++ b/src/main/java/com/example/aitest/dao/redis/TokenRedis.java @@ -0,0 +1,31 @@ +package com.example.aitest.dao.redis; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +@Repository +public class TokenRedis implements RedisUtil { + + @Resource + StringRedisTemplate stringRedisTemplate; + + @Override + public void addRedis(String key, String value) { + ValueOperations valueOperations = stringRedisTemplate.opsForValue(); + valueOperations.set(key, value, 60, TimeUnit.MINUTES); + } + + @Override + public void delRedis(String key) { + + } + + @Override + public String getRedis(String key) { + return stringRedisTemplate.opsForValue().get(key); + } +} diff --git a/src/main/java/com/example/aitest/jwt/InterceptorConfig.java b/src/main/java/com/example/aitest/jwt/InterceptorConfig.java new file mode 100644 index 0000000..03b9e38 --- /dev/null +++ b/src/main/java/com/example/aitest/jwt/InterceptorConfig.java @@ -0,0 +1,41 @@ +package com.example.aitest.jwt; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.ArrayList; + +@Configuration +public class InterceptorConfig implements WebMvcConfigurer { + TokenInterceptor tokenInterceptor; + + public InterceptorConfig(TokenInterceptor tokenInterceptor) {//构造函数 + this.tokenInterceptor = tokenInterceptor; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) {//配置拦截器 + System.out.println("拦截器被配置了"); + ArrayList excludePath = new ArrayList<>(); + excludePath.add("/login");//登录 + excludePath.add("/checkCode"); + excludePath.add("/sendCode"); + excludePath.add("/register");//注册 + excludePath.add("/register"); + excludePath.add("/index/modifyHead"); + registry.addInterceptor(tokenInterceptor)//注册拦截器 + .addPathPatterns("/**")//拦截所有请求 + .excludePathPatterns(excludePath);//添加拦截白名单 + WebMvcConfigurer.super.addInterceptors(registry);//调用父接口 + } + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**").allowCredentials(true)//允许携带cookie + .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")//允许访问的方法 + .allowedOriginPatterns("*")//允许的跨域访问地址 + .maxAge(3600 * 24);//options缓存时间 + } +} diff --git a/src/main/java/com/example/aitest/jwt/JWTUtil.java b/src/main/java/com/example/aitest/jwt/JWTUtil.java new file mode 100644 index 0000000..7397672 --- /dev/null +++ b/src/main/java/com/example/aitest/jwt/JWTUtil.java @@ -0,0 +1,34 @@ +package com.example.aitest.jwt; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; + + +public class JWTUtil { + private static final String tokenPassword = "uziCjb"; + + public static String sign(String username) {//用用户名作为被加密的对象 + String token; + + token = JWT.create()//生成jwt令牌,加密过程 + .withIssuer("llh") + .withClaim("username", username) + .sign(Algorithm.HMAC256(tokenPassword)); + return token;//返回加密后的token + } + + public static String verify(String token) { + JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(tokenPassword)).withIssuer("llh").build();//构建一个jwt解码器 + DecodedJWT jwtToken = jwtVerifier.verify(token);//解码 + if (token.isEmpty()) {//若token为空则返回false拦截 + return null; + } else { + System.out.println("认证通过:"); + System.out.println("issuer: " + jwtToken.getIssuer()); + System.out.println("username: " + jwtToken.getClaim("username").asString()); + return jwtToken.getClaim("username").asString(); + } + } +} diff --git a/src/main/java/com/example/aitest/jwt/TokenInterceptor.java b/src/main/java/com/example/aitest/jwt/TokenInterceptor.java new file mode 100644 index 0000000..672a73c --- /dev/null +++ b/src/main/java/com/example/aitest/jwt/TokenInterceptor.java @@ -0,0 +1,57 @@ +package com.example.aitest.jwt; + +import com.example.aitest.dao.redis.RedisUtil; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Component +public class TokenInterceptor implements HandlerInterceptor { + @Resource(name = "tokenRedis") + RedisUtil redisUtil;//注册服务 + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + System.out.println("触发拦截"); + String token = request.getHeader("Token"); +// System.out.println(token + "检查一下token是啥"); +// Enumeration headerNames = request.getHeaderNames(); +// while (headerNames.hasMoreElements()) { +// String headerName = headerNames.nextElement(); +// String headerValue = request.getHeader(headerName); +// System.out.println(headerName + ": " + headerValue); +// } + try { + if (request.getMethod().equals("OPTIONS")) {//检查是否为跨域请求 + return true; + } + + response.setCharacterEncoding("utf-8"); + + if (token != null) { + String verifyToken = JWTUtil.verify(token); + + if (redisUtil.getRedis(verifyToken) != null) { + response.setStatus(200);//设置状态码为正常,即通过登录验证 + System.out.println("通过拦截器"); + return true; + } else { + response.setStatus(401); + return false;//redis里没有token,即登录超时 + } + } else { + response.setStatus(402); + return false;//请求头不带token + } + + } catch (Exception exception) { + response.setStatus(500);//发生了不可预测的错误 + throw new RuntimeException(); + } + + + } +} diff --git a/src/main/java/com/example/aitest/mapper/UserMapper.java b/src/main/java/com/example/aitest/mapper/UserMapper.java new file mode 100644 index 0000000..1f79d9d --- /dev/null +++ b/src/main/java/com/example/aitest/mapper/UserMapper.java @@ -0,0 +1,14 @@ +package com.example.aitest.mapper; + +import com.example.aitest.pojo.User; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface UserMapper { + + User login(User user); + + void register(User user); + + User getUser(User user); +} diff --git a/src/main/java/com/example/aitest/pojo/User.java b/src/main/java/com/example/aitest/pojo/User.java new file mode 100644 index 0000000..e6729b7 --- /dev/null +++ b/src/main/java/com/example/aitest/pojo/User.java @@ -0,0 +1,10 @@ +package com.example.aitest.pojo; + +import lombok.Data; + +@Data +public class User { + private String username; + private String password; + private String phone; +} diff --git a/src/main/java/com/example/aitest/service/UserService.java b/src/main/java/com/example/aitest/service/UserService.java new file mode 100644 index 0000000..1119fa4 --- /dev/null +++ b/src/main/java/com/example/aitest/service/UserService.java @@ -0,0 +1,16 @@ +package com.example.aitest.service; + +import com.example.aitest.pojo.User; +import org.springframework.stereotype.Service; + +import java.security.NoSuchAlgorithmException; + +public interface UserService { + + String login(User user) throws NoSuchAlgorithmException; + + String register(User user) throws NoSuchAlgorithmException; + + + +} diff --git a/src/main/java/com/example/aitest/service/impl/UserServiceImpl.java b/src/main/java/com/example/aitest/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..2a1cb16 --- /dev/null +++ b/src/main/java/com/example/aitest/service/impl/UserServiceImpl.java @@ -0,0 +1,60 @@ +package com.example.aitest.service.impl; + +import com.example.aitest.dao.redis.RedisUtil; +import com.example.aitest.jwt.JWTUtil; +import com.example.aitest.mapper.UserMapper; +import com.example.aitest.pojo.User; +import com.example.aitest.service.UserService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +@Service +public class UserServiceImpl implements UserService { + + @Resource + public UserMapper userMapper; + @Resource(name = "tokenRedis") + public RedisUtil tokenRedis; + @Override + public String login(User user) throws NoSuchAlgorithmException { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(user.getPassword().getBytes()); + byte[] digest = md5.digest(); + user.setPassword(parseByte2HexStr(digest)); + User loginUser = userMapper.login(user); + System.out.println(loginUser); + if (loginUser != null) { + String token = JWTUtil.sign(user.getPhone()); + tokenRedis.addRedis(user.getPhone(), token); + return token; + } + return "登录失败"; + } + + @Override + public String register(User user) throws NoSuchAlgorithmException { + if (userMapper.getUser(user) != null) { + return "用户已存在"; + } + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(user.getPassword().getBytes()); + byte[] digest = md5.digest(); + user.setPassword(parseByte2HexStr(digest)); + userMapper.register(user); + return "注册成功"; + } + + private String parseByte2HexStr(byte[] buf) { + StringBuilder sb = new StringBuilder(); + for (byte b : buf) { + String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 8754b1c..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.application.name=AITest -server.port=8081 \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..ce4bde9 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,16 @@ +spring: + application: + name: AITest + redis: + port: 6379 +# password: ob666666 + host: localhost + datasource: + username: root + password: ob666666 + url: jdbc:mysql://localhost:3306/AITest + driver-class-name: com.mysql.cj.jdbc.Driver +mybatis: + mapper-locations: classpath:mapper/*.xml +server: + port: 8081 diff --git a/src/main/resources/mapper/UserMapper.xml b/src/main/resources/mapper/UserMapper.xml new file mode 100644 index 0000000..4ba123a --- /dev/null +++ b/src/main/resources/mapper/UserMapper.xml @@ -0,0 +1,15 @@ + + + + + + + + + insert into user (phone, password, username)values(#{phone}, #{password}, #{username}) + + diff --git a/src/test/java/com/example/aitest/MD5Test.java b/src/test/java/com/example/aitest/MD5Test.java new file mode 100644 index 0000000..421ca5d --- /dev/null +++ b/src/test/java/com/example/aitest/MD5Test.java @@ -0,0 +1,32 @@ +package com.example.aitest; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +@SpringBootTest +public class MD5Test { + + @Test + public void test() throws NoSuchAlgorithmException { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update("ob666666".getBytes()); + byte[] digest = md5.digest(); + String s = parseByte2HexStr(digest); + System.out.println(s); + } + private String parseByte2HexStr(byte buf[]) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < buf.length; i++) { + String hex = Integer.toHexString(buf[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + +}