This commit is contained in:
Administrator
2024-05-09 18:08:42 +08:00
commit fb42ddf9bb
92 changed files with 3072 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.idea
*.iml
target
logs

70
common/pom.xml Normal file
View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>security-api-demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common</artifactId>
<dependencies>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<!--commons-langs-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!--日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,16 @@
package com.demo.constant;
/**
* @Description:
* @Author: Rosh
* @Date: 2021/10/27 09:53
*/
public final class RSAConstant {
private RSAConstant(){
}
public static String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCFtTlL61IqIGd+fRLUhJ0MjsqFXFJswCohJ45m51WvbxDPRP3gllW0WChk74D5JEOpMDSWo4C7RfoGlBRNW7kQ6qYGukYZ5jgYpzoT0+gp3on96fQXEyQJysv9xiTPIdmSXXVVj1HAOJw29RbzxIVKUSzzPXvEtXRTtCC1+wkAJQIDAQAB";
public static final String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIW1OUvrUiogZ359EtSEnQyOyoVcUmzAKiEnjmbnVa9vEM9E/eCWVbRYKGTvgPkkQ6kwNJajgLtF+gaUFE1buRDqpga6RhnmOBinOhPT6Cneif3p9BcTJAnKy/3GJM8h2ZJddVWPUcA4nDb1FvPEhUpRLPM9e8S1dFO0ILX7CQAlAgMBAAECgYBC4amtbiKFa/wY61tV7pfYRjzLhKi+OUlZmD3E/4Z+4KGZ7DrJ8qkgMtDR3HO5LAikQrare1HTW2d7juqw32ascu+uDObf4yrYNKin+ZDLUYvIDfLhThPxnZJwQ/trdtfxO3VM//XbwZacmwYbAsYW/3QPUXwwOPAgbC2oth8kqQJBANKLyXcdjZx4cwJVl7xNeC847su8y6bPpcBASsaQloCIPiNBIg1h76dpfEGIQBYWJWbBsxtHe/MhOmz7fNFDS2sCQQCiktYZR0dZNH4eNX329LoRuBiltpr9tf36rVOlKr1GSHkLYEHF2qtyXV2mdrY8ZWpvuo3qm1oSLaqmop2rN9avAkBHk85B+IIUF77BpGeZVJzvMOO9z8lMRHuNCE5jgvQnbinxwkrZUdovh+T+QlvHJnBApslFFOBGn51FP5oHamFRAkEAmwZmPsinkrrpoKjlqz6GyCrC5hKRDWoj/IyXfKKaxpCJTH3HeoIghvfdO8Vr1X/n1Q8SESt+4mLFngznSMQAZQJBAJx07bCFYbA2IocfFV5LTEYTIiUeKdue2NP2yWqZ/+tB5H7jNwQTJmX1mn0W/sZm4+nJM7SjfETpNZhH49+rV6U=";
}

View File

@@ -0,0 +1,13 @@
package com.demo.constant;
public class UserConstant {
private UserConstant() {
}
public static final String TOKEN = "token";
}

View File

@@ -0,0 +1,22 @@
package com.demo.excepiton;
import lombok.Getter;
/**
* @Description:
* @Author: Rosh
* @Date: 2021/8/10 17:39
*/
@Getter
public class RSAException extends RuntimeException {
private final String message;
public RSAException(String message) {
this.message = message;
}
}

View File

@@ -0,0 +1,88 @@
package com.demo.utils;
import com.demo.excepiton.RSAException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class RSAUtils {
public static final String PUBLIC_KEY = "public_key";
public static final String PRIVATE_KEY = "private_key";
public static Map<String, String> generateRasKey() {
Map<String, String> rs = new HashMap<>();
try {
// KeyPairGenerator类用于生成公钥和私钥对基于RSA算法生成对象
KeyPairGenerator keyPairGen = null;
keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024, new SecureRandom());
// 生成一个密钥对保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥 公钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
// 将公钥和私钥保存到Map
rs.put(PUBLIC_KEY, publicKeyString);
rs.put(PRIVATE_KEY, privateKeyString);
} catch (Exception e) {
throw new RSAException("RsaUtils invoke genKeyPair failed.");
}
return rs;
}
public static String encrypt(String str, String publicKey) {
try {
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
throw new RSAException("RsaUtils invoke encrypt failed.");
}
}
public static String decrypt(String str, String privateKey) {
try {
//64位解码加密后的字符串
byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
//base64编码的私钥
byte[] decoded = Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
return new String(cipher.doFinal(inputByte));
} catch (Exception e) {
throw new RSAException("RsaUtils invoke decrypt failed.");
}
}
}

View File

@@ -0,0 +1,75 @@
package com.demo.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.UUID;
/**
* @Description:
* @Author: Rosh
* @Date: 2021/8/11 14:21
*/
public final class TokenUtils {
private static final String SIGN_KEY = "STREAM_TOKEN";
/**
*jwt 有效期为3天
*/
private static final Long JWT_EXPIRE_TIME_LONG = 1000 * 60 * 60 * 24 * 3L;
private TokenUtils() {
}
public static String createToken(String str) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
SecretKey secretKey = createSecretKey();
JwtBuilder builder = Jwts.builder()
.setId(UUID.randomUUID().toString())
.setIssuedAt(now)
.setSubject(str)
.signWith(signatureAlgorithm, secretKey);
long expMillis = System.currentTimeMillis() + JWT_EXPIRE_TIME_LONG;
Date exp = new Date(expMillis);
//token过期时间
builder.setExpiration(exp);
return builder.compact();
}
private static SecretKey createSecretKey() {
byte[] encodedKey = Base64.decodeBase64(SIGN_KEY);
return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
}
public static Claims getClaim(String token) {
SecretKey secretKey = createSecretKey();
try {
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
} catch (Exception ignored) {
return null;
}
}
}

View File

@@ -0,0 +1,105 @@
package com.common;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
public class RSAEncrypt {
private static Map<Integer, String> keyMap = new HashMap<Integer, String>(); //用于封装随机产生的公钥与私钥
public static void main(String[] args) throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("username", "rosh");
jsonObject.put("password", "123456");
//生成公钥和私钥
genKeyPair();
//加密字符串
String message = jsonObject.toJSONString();
System.out.println("随机生成的公钥为:" + keyMap.get(0));
System.out.println("随机生成的私钥为:" + keyMap.get(1));
String messageEn = encrypt(message,keyMap.get(0));
System.out.println(message + "\t加密后的字符串为:" + messageEn);
String messageDe = decrypt(messageEn,keyMap.get(1));
System.out.println("还原后的字符串为:" + messageDe);
}
/**
* 随机生成密钥对
* @throws NoSuchAlgorithmException
*/
public static void genKeyPair() throws NoSuchAlgorithmException {
// KeyPairGenerator类用于生成公钥和私钥对基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器密钥大小为96-1024位
keyPairGen.initialize(1024,new SecureRandom());
// 生成一个密钥对保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
// 将公钥和私钥保存到Map
keyMap.put(0,publicKeyString); //0表示公钥
keyMap.put(1,privateKeyString); //1表示私钥
}
/**
* RSA公钥加密
*
* @param str
* 加密字符串
* @param publicKey
* 公钥
* @return 密文
* @throws Exception
* 加密过程中的异常信息
*/
public static String encrypt( String str, String publicKey ) throws Exception{
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
/**
* RSA私钥解密
*
* @param str
* 加密字符串
* @param privateKey
* 私钥
* @return 铭文
* @throws Exception
* 解密过程中的异常信息
*/
public static String decrypt(String str, String privateKey) throws Exception{
//64位解码加密后的字符串
byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
//base64编码的私钥
byte[] decoded = Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}
}

View File

@@ -0,0 +1,12 @@
package com.common;
/**
* @Description:
* @Author: rosh
* @Date: 2021/10/25 23:32
*/
public class test {
public static void main(String[] args) {
}
}

62
gateway/pom.xml Normal file
View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>security-api-demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--spring cloud alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!--依赖common-->
<dependency>
<groupId>org.example</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 添加spring boot 的依赖 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.0.RELEASE</version>
<configuration>
<mainClass>com.demo.gateway.GatewayApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,23 @@
package com.demo.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Description:
* @Author: rosh
* @Date: 2021/10/24 23:34
*/
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class);
}
}

View File

@@ -0,0 +1,49 @@
package com.demo.gateway.config;
import com.alibaba.fastjson.JSONObject;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
/**
* @Description:
* @Author: Rosh
* @Date: 2021/10/27 09:35
*/
public final class FilterUtils {
private FilterUtils() {
}
public static Mono<Void> invalidToken(ServerWebExchange exchange) {
JSONObject json = new JSONObject();
json.put("code", HttpStatus.UNAUTHORIZED.value());
json.put("msg", "无效的token");
return buildReturnMono(json, exchange);
}
public static Mono<Void> invalidUrl(ServerWebExchange exchange){
JSONObject json = new JSONObject();
json.put("code", HttpStatus.BAD_REQUEST.value());
json.put("msg", "无效的请求");
return buildReturnMono(json, exchange);
}
public static Mono<Void> buildReturnMono(JSONObject json, ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
byte[] bits = json.toJSONString().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
}

View File

@@ -0,0 +1,26 @@
package com.demo.gateway.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
@Configuration
public class GatewayCrosConfiguration {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsWebFilter(source);
}
}

View File

@@ -0,0 +1,29 @@
package com.demo.gateway.exception;
import com.alibaba.fastjson.JSONObject;
import com.demo.excepiton.RSAException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
public abstract class AbstractExceptionHandler {
protected JSONObject buildErrorMap(Throwable ex) {
JSONObject json = new JSONObject();
if (ex instanceof RSAException || ex instanceof IllegalArgumentException) {
json.put("code", HttpStatus.BAD_REQUEST.value());
if (StringUtils.isNotBlank(ex.getMessage())){
json.put("msg", ex.getMessage());
}else {
json.put("msg", "无效的请求");
}
} else {
json.put("code", HttpStatus.BAD_REQUEST.value());
json.put("msg", "未知错误联系管理员");
}
return json;
}
}

View File

@@ -0,0 +1,31 @@
package com.demo.gateway.exception;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import java.util.Collections;
import java.util.List;
@Configuration
public class GatewayExceptionConfig {
@Primary
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ErrorWebExceptionHandler errorWebExceptionHandler(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
GatewayExceptionHandler gatewayExceptionHandler = new GatewayExceptionHandler();
gatewayExceptionHandler.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList));
gatewayExceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
gatewayExceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
return gatewayExceptionHandler;
}
}

View File

@@ -0,0 +1,99 @@
package com.demo.gateway.exception;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Slf4j
public class GatewayExceptionHandler extends AbstractExceptionHandler implements ErrorWebExceptionHandler {
private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();
private List<HttpMessageWriter<?>> messageWriters = Collections.emptyList();
private List<ViewResolver> viewResolvers = Collections.emptyList();
private ThreadLocal<JSONObject> exceptionHandlerResult = new ThreadLocal<>();
public void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {
Assert.notNull(messageReaders, "'messageReaders' must not be null");
this.messageReaders = messageReaders;
}
public void setViewResolvers(List<ViewResolver> viewResolvers) {
this.viewResolvers = viewResolvers;
}
public void setMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
Assert.notNull(messageWriters, "'messageWriters' must not be null");
this.messageWriters = messageWriters;
}
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
JSONObject errorInfo = super.buildErrorMap(ex);
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
}
exceptionHandlerResult.set(errorInfo);
ServerRequest newRequest = ServerRequest.create(exchange, this.messageReaders);
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse).route(newRequest)
.switchIfEmpty(Mono.error(ex))
.flatMap(handler -> handler.handle(newRequest))
.flatMap(response -> write(exchange, response));
}
protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
Map<String, Object> result = exceptionHandlerResult.get();
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(result));
}
private Mono<? extends Void> write(ServerWebExchange exchange,
ServerResponse response) {
exchange.getResponse().getHeaders().setContentType(response.headers().getContentType());
return response.writeTo(exchange, new ResponseContext());
}
private class ResponseContext implements ServerResponse.Context {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return GatewayExceptionHandler.this.messageWriters;
}
@Override
public List<ViewResolver> viewResolvers() {
return GatewayExceptionHandler.this.viewResolvers;
}
}
}

View File

@@ -0,0 +1,202 @@
package com.demo.gateway.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.Md5Utils;
import com.demo.gateway.config.FilterUtils;
import com.demo.gateway.pojo.MyCachedBodyOutputMessage;
import com.demo.gateway.utils.AESUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
/**
* @Description:
* @Author: rosh
* @Date: 2021/10/26 22:24
*/
@Configuration
@Component
public class RequestEncryptionGlobalFilter implements GlobalFilter, Ordered {
private static final String AES_SECURTY = "MTIzNDU2Nzg5MTIzNDU2Nw==";
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final String ERROR_MESSAGE = "拒绝服务";
private static final String SIGN_ERROR_MESSAGE = "签名过期";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1 获取时间戳
Long dateTimestamp = getDateTimestamp(exchange.getRequest().getHeaders());
//2 获取RequestId
String requestId = getRequestId(exchange.getRequest().getHeaders());
//3 获取签名
String sign = getSign(exchange.getRequest().getHeaders());
//4 如果是登录不校验Token
// String requestUrl = exchange.getRequest().getPath().value();
// AntPathMatcher pathMatcher = new AntPathMatcher();
// if (!pathMatcher.match("/user/login", requestUrl)) {
// String token = exchange.getRequest().getHeaders().getFirst(UserConstant.TOKEN);
// Claims claim = TokenUtils.getClaim(token);
// if (StringUtils.isBlank(token) || claim == null) {
// return FilterUtils.invalidToken(exchange);
// }
// }
//5 修改请求参数,并获取请求参数
Map<String, Object> paramMap;
try {
paramMap = updateRequestParam(exchange);
} catch (Exception e) {
return FilterUtils.invalidUrl(exchange);
}
//6 获取请求体,修改请求体
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
String encrypt = AESUtil.decrypt(body, AES_SECURTY);
JSONObject jsonObject = JSON.parseObject(encrypt);
for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
paramMap.put(entry.getKey(), entry.getValue());
}
checkSign(sign, dateTimestamp, requestId, paramMap);
return Mono.just(encrypt);
});
//创建BodyInserter修改请求体
BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
headers.remove(HttpHeaders.CONTENT_LENGTH);
//创建CachedBodyOutputMessage并且把请求param加入,初始化校验信息
MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers);
outputMessage.initial(paramMap, requestId, sign, dateTimestamp);
//修改响应体
MyCachedBodyOutputMessage repOutputMessage = new MyCachedBodyOutputMessage(exchange, headers);
repOutputMessage.getBody();
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
Flux<DataBuffer> body = outputMessage.getBody();
if (body.equals(Flux.empty())) {
//验证签名
checkSign(outputMessage.getSign(), outputMessage.getDateTimestamp(), outputMessage.getRequestId(), outputMessage.getParamMap());
}
return outputMessage.getBody();
}
};
return chain.filter(exchange.mutate().request(decorator).build());
}));
}
public void checkSign(String sign, Long dateTimestamp, String requestId, Map<String, Object> paramMap) {
String str = JSON.toJSONString(paramMap) + requestId + dateTimestamp;
String tempSign = Md5Utils.getMD5(str.getBytes());
if (!tempSign.equals(sign)) {
throw new IllegalArgumentException(SIGN_ERROR_MESSAGE);
}
}
/**
* 修改前端传的参数
*/
private Map<String, Object> updateRequestParam(ServerWebExchange exchange) throws NoSuchFieldException, IllegalAccessException {
ServerHttpRequest request = exchange.getRequest();
URI uri = request.getURI();
String query = uri.getQuery();
if (StringUtils.isNotBlank(query) && query.contains("param")) {
return getParamMap(query);
}
return new TreeMap<>();
}
private Map<String, Object> getParamMap(String param) {
Map<String, Object> map = new TreeMap<>();
String[] split = param.split("&");
for (String str : split) {
String[] params = str.split("=");
map.put(params[0], params[1]);
}
return map;
}
private String getSign(HttpHeaders headers) {
List<String> list = headers.get("sign");
if (CollectionUtils.isEmpty(list)) {
throw new IllegalArgumentException(ERROR_MESSAGE);
}
return list.get(0);
}
private Long getDateTimestamp(HttpHeaders httpHeaders) {
List<String> list = httpHeaders.get("timestamp");
if (CollectionUtils.isEmpty(list)) {
throw new IllegalArgumentException(ERROR_MESSAGE);
}
long timestamp = Long.parseLong(list.get(0));
long currentTimeMillis = System.currentTimeMillis();
//有效时长为5分钟
if (currentTimeMillis - timestamp > 1000 * 60 * 5) {
throw new IllegalArgumentException(ERROR_MESSAGE);
}
return timestamp;
}
private String getRequestId(HttpHeaders headers) {
List<String> list = headers.get("requestId");
if (CollectionUtils.isEmpty(list)) {
throw new IllegalArgumentException(ERROR_MESSAGE);
}
String requestId = list.get(0);
//如果requestId存在redis中直接返回
String temp = redisTemplate.opsForValue().get(requestId);
if (StringUtils.isNotBlank(temp)) {
throw new IllegalArgumentException("RequestId 非法");
}
redisTemplate.opsForValue().set(requestId, requestId, 5, TimeUnit.MINUTES);
return requestId;
}
@Override
public int getOrder() {
return 80;
}
}

View File

@@ -0,0 +1,95 @@
package com.demo.gateway.filter;
import com.demo.gateway.utils.AESUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.annotation.NonNull;
import java.nio.charset.StandardCharsets;
/**
* 响应 Body 加密 过滤器
*
* @author xuxiaowei
* @see ServerHttpResponseDecorator
* @since 0.0.1
*/
@Slf4j
@Configuration
@Component
public class ResponseEncryptionGlobalFilter implements GlobalFilter, Ordered {
private static final String AES_SECURTY = "MTIzNDU2Nzg5MTIzNDU2Nw=="; //1234567891234567
/**
* 加密 过滤器 优先级
* <p>
* 响应数据过滤器优先级需要小于 0否则将无效
*/
@Override
public int getOrder() {
return -1;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.debug("触发");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
ServerHttpResponseDecorator decorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
@NonNull
@Override
public Mono<Void> writeWith(@NonNull Publisher<? extends DataBuffer> body) {
@SuppressWarnings("unchecked")
Flux<? extends DataBuffer> fluxDataBuffer = (Flux<? extends DataBuffer>) body;
return super.writeWith(fluxDataBuffer.buffer()
.map(dataBuffer -> {
DataBuffer join = exchange.getResponse().bufferFactory().join(dataBuffer);
byte[] bytes = new byte[join.readableByteCount()];
join.read(bytes);
DataBufferUtils.release(join);
log.debug("加密前 body{}", new String(bytes));
byte[] encryption;
try {
//加密
encryption = AESUtil.encrypt(new String(bytes), AES_SECURTY).getBytes();
} catch (Exception e) {
encryption = bytes;
log.error("数据类型不是 JSON不加密", e);
}
log.debug("加密后 body{}", new String(encryption, StandardCharsets.UTF_8));
return exchange.getResponse().bufferFactory().wrap(encryption);
})
);
}
};
return chain.filter(exchange.mutate().response(decorator).build());
}
}

View File

@@ -0,0 +1,51 @@
package com.demo.gateway.pojo;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.http.HttpHeaders;
import org.springframework.web.server.ServerWebExchange;
import java.util.Map;
/**
* @Description:
* @Author: Rosh
* @Date: 2021/10/27 11:03
*/
public class MyCachedBodyOutputMessage extends CachedBodyOutputMessage {
private Map<String, Object> paramMap;
private Long dateTimestamp;
private String requestId;
private String sign;
public MyCachedBodyOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) {
super(exchange, httpHeaders);
}
public void initial(Map<String, Object> paramMap, String requestId, String sign, Long dateTimestamp) {
this.paramMap = paramMap;
this.requestId = requestId;
this.sign = sign;
this.dateTimestamp = dateTimestamp;
}
public Map<String, Object> getParamMap() {
return paramMap;
}
public Long getDateTimestamp() {
return dateTimestamp;
}
public String getRequestId() {
return requestId;
}
public String getSign() {
return sign;
}
}

View File

@@ -0,0 +1,12 @@
package com.demo.gateway;
import com.demo.gateway.utils.AESUtil;
public class test {
public static void main(String[] args) {
String str = "uMDI+g2bagWZ6+wlwBGQYjPFu1pJ8oA39/HzrpZT7nbUDdZogctMTxiPY //vF2stkEFLwjhiJTlPZObyLKInxjIzojhVH3gIMVQ0mcbmp3fNbYVds8cN9jkSYxEgp1eWCXbPCDxKsTuXD6q671vlNGg2m7Qu/rW+2jelZWGYVse2KI6rLfkB54r23ZVHOU2gNEC6DYIvn2+vdtOe89pd7hM1XbRyBHYVjwM/0TTHrOU4k8d0oP5/vbmLHFUgYpXq4R4ZxsXa70+/w9xAjRU+THnItxiLx2HZgCros+F2I5uT0a4lBXtOZVUGYJe2PX08oi2ySmrgVrBYQhWX4z7/nW+0DCbBbOcT2rS9zWflFqUKOseKRRVrSE02Zk6+RgfX9yn/BTbhPjJezI9NdbZYQ==";
//String encrypt = AESUtil.encrypt(str, "MTIzNDU2Nzg5MTIzNDU2Nw==");
String decrypt = AESUtil.decrypt(str, "MTIzNDU2Nzg5MTIzNDU2Nw==");
System.out.println(decrypt);
}
}

View File

@@ -0,0 +1,57 @@
package com.demo.gateway.utils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AESUtil {
static String base64EncodedIV = "MTIzNDU2Nzg5MTIzNDU2Nw=="; //1234567891234567
public static String decrypt(String encryptedText, String base64EncodedKey) {
try {
// 解码密钥
byte[] decodedKey = Base64.getDecoder().decode(base64EncodedKey);
SecretKeySpec keySpec = new SecretKeySpec(decodedKey, "AES");
byte[] decodedIV = Base64.getDecoder().decode(base64EncodedIV);
IvParameterSpec ivSpec = new IvParameterSpec(decodedIV);
// 创建 AES 密码器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
// 解密
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
// 将解密后的字节数组转换为字符串并返回
return new String(decryptedBytes);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String encrypt(String plainText, String base64EncodedKey) {
try {
// 解码密钥
byte[] decodedKey = Base64.getDecoder().decode(base64EncodedKey);
SecretKeySpec keySpec = new SecretKeySpec(decodedKey, "AES");
byte[] decodedIV = Base64.getDecoder().decode(base64EncodedIV);
IvParameterSpec ivSpec = new IvParameterSpec(decodedIV);
// 创建 AES 密码器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
// 加密
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
// 将加密后的字节数组和 Base64 编码的初始化向量一起返回
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,23 @@
server:
port: 9000
spring:
application:
name: gateway-service
cloud:
nacos:
discovery:
server-addr: 192.168.202.220:8848
gateway:
routes:
- id: demo-one
uri: lb://libirary-service
predicates:
- Path=/**
# predicates:
# - Path=/api/user/**
# filters:
# - RewritePath=/api/(?<segment>.*),/$\{segment}
redis:
port: 6379
host: 127.0.0.1

109
library/pom.xml Normal file
View File

@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>library</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>library</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version> <!-- 版本号可以根据你的需求进行更改 -->
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version> <!-- 版本号可以根据你的需求进行更改 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.16</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.4</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.1 </version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,18 @@
package com.example.library;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.example.library.mapper")
public class LibraryApplication {
public static void main(String[] args) {
SpringApplication.run(LibraryApplication.class, args);
}
}

View File

@@ -0,0 +1,11 @@
package com.example.library;
public class LoginUser {
private static int visitCount = 0;
public static void addVisitCount() {
LoginUser.visitCount++;
}
public static int getVisitCount() {
return LoginUser.visitCount;
}
}

View File

@@ -0,0 +1,28 @@
package com.example.library.commom;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* mybatis-plus 分页插件
*/
@Configuration
@MapperScan("com.example.demo.mapper")
@MapperScan("com.example.demo.service")
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

View File

@@ -0,0 +1,65 @@
package com.example.library.commom;
public class Result<T> {
private String code;
private String msg;
private T data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Result() {
}
public Result(T data) {
this.data = data;
}
public static Result success() {
Result result = new Result<>();
result.setCode("0");
result.setMsg("成功");
return result;
}
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>(data);
result.setCode("0");
result.setMsg("成功");
return result;
}
public static <T> Result<T> noAuth() {
Result<T> result = new Result<>();
result.setCode("401");
result.setMsg("error");
return result;
}
public static Result error(String code, String msg) {
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
return result;
}
}

View File

@@ -0,0 +1,62 @@
package com.example.library.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.library.commom.Result;
import com.example.library.entity.Book;
import com.example.library.mapper.BookMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/book")
public class BookController {
@Resource
BookMapper BookMapper;
@PostMapping
public Result<?> save(@RequestBody Book Book){
BookMapper.insert(Book);
return Result.success();
}
@PutMapping
public Result<?> update(@RequestBody Book Book){
BookMapper.updateById(Book);
return Result.success();
}
// 批量删除
@PostMapping("/deleteBatch")
public Result<?> deleteBatch(@RequestBody List<Integer> ids){
BookMapper.deleteBatchIds(ids);
return Result.success();
}
@DeleteMapping("/{id}")
public Result<?> delete(@PathVariable Long id){
BookMapper.deleteById(id);
return Result.success();
}
@GetMapping
public Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "") String search1,
@RequestParam(defaultValue = "") String search2,
@RequestParam(defaultValue = "") String search3){
LambdaQueryWrapper<Book> wrappers = Wrappers.<Book>lambdaQuery();
if(StringUtils.isNotBlank(search1)){
wrappers.like(Book::getIsbn,search1);
}
if(StringUtils.isNotBlank(search2)){
wrappers.like(Book::getName,search2);
}
if(StringUtils.isNotBlank(search3)){
wrappers.like(Book::getAuthor,search3);
}
Page<Book> BookPage =BookMapper.selectPage(new Page<>(pageNum,pageSize), wrappers);
return Result.success(BookPage);
}
}

View File

@@ -0,0 +1,99 @@
package com.example.library.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.library.commom.Result;
import com.example.library.entity.BookWithUser;
import com.example.library.mapper.BookWithUserMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/bookwithuser")
public class BookWithUserController {
@Resource
BookWithUserMapper BookWithUserMapper;
//
// @PostMapping
// public Result<?> save(@RequestBody Book Book){
// BookMapper.insert(Book);
// return Result.success();
// }
// // 批量删除
// @PostMapping("/deleteBatch")
// public Result<?> deleteBatch(@RequestBody List<Integer> ids){
// BookMapper.deleteBatchIds(ids);
// return Result.success();
// }
// @PutMapping
// public Result<?> update(@RequestBody Book Book){
// BookMapper.updateById(Book);
// return Result.success();
// }
// @DeleteMapping("/{id}")
// public Result<?> delete(@PathVariable Long id){
// BookMapper.deleteById(id);
// return Result.success();
// }
@PostMapping("/insertNew")
public Result<?> insertNew(@RequestBody BookWithUser BookWithUser){
BookWithUserMapper.insert(BookWithUser);
return Result.success();
}
@PostMapping
public Result<?> update(@RequestBody BookWithUser BookWithUser){
UpdateWrapper<BookWithUser> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("isbn",BookWithUser.getIsbn()).eq("id",BookWithUser.getId());
BookWithUserMapper.update(BookWithUser, updateWrapper);
return Result.success();
}
//删除一条记录
@PostMapping("/deleteRecord")
public Result<?> deleteRecord(@RequestBody BookWithUser BookWithUser){
Map<String,Object> map = new HashMap<>();
map.put("isbn",BookWithUser.getIsbn());
map.put("id",BookWithUser.getId());
BookWithUserMapper.deleteByMap(map);
return Result.success();
}
@PostMapping("/deleteRecords")
public Result<?> deleteRecords(@RequestBody List<BookWithUser> BookWithUsers){
int len = BookWithUsers.size();
for(int i=0;i<len;i++) {
BookWithUser curRecord = BookWithUsers.get(i);
Map<String,Object> map = new HashMap<>();
map.put("isbn",curRecord.getIsbn());
map.put("id",curRecord.getId());
BookWithUserMapper.deleteByMap(map);
}
return Result.success();
}
@GetMapping
public Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "") String search1,
@RequestParam(defaultValue = "") String search2,
@RequestParam(defaultValue = "") String search3){
LambdaQueryWrapper<BookWithUser> wrappers = Wrappers.<BookWithUser>lambdaQuery();
if(StringUtils.isNotBlank(search1)){
wrappers.like(BookWithUser::getIsbn,search1);
}
if(StringUtils.isNotBlank(search2)){
wrappers.like(BookWithUser::getBookName,search2);
}
if(StringUtils.isNotBlank(search3)){
wrappers.like(BookWithUser::getId,search3);
}
Page<BookWithUser> BookPage =BookWithUserMapper.selectPage(new Page<>(pageNum,pageSize), wrappers);
return Result.success(BookPage);
}
}

View File

@@ -0,0 +1,47 @@
package com.example.library.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.library.LoginUser;
import com.example.library.commom.Result;
import com.example.library.entity.Book;
import com.example.library.entity.LendRecord;
import com.example.library.entity.User;
import com.example.library.mapper.BookMapper;
import com.example.library.mapper.LendRecordMapper;
import com.example.library.mapper.UserMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/dashboard")
public class DashboardController {
@Resource
private UserMapper userMapper;
@Resource
private LendRecordMapper lendRecordMapper;
@Resource
private BookMapper bookMapper;
@GetMapping
public Result<?> dashboardrecords(){
int visitCount = LoginUser.getVisitCount();
QueryWrapper<User> queryWrapper1=new QueryWrapper();
int userCount = userMapper.selectCount(queryWrapper1);
QueryWrapper<LendRecord> queryWrapper2=new QueryWrapper();
int lendRecordCount = lendRecordMapper.selectCount(queryWrapper2);
QueryWrapper<Book> queryWrapper3=new QueryWrapper();
int bookCount = bookMapper.selectCount(queryWrapper3);
Map<String, Object> map = new HashMap<>();//键值对形式
map.put("visitCount", visitCount);//放置visitCount到map中
map.put("userCount", userCount);
map.put("lendRecordCount", lendRecordCount);
map.put("bookCount", bookCount);
return Result.success(map);
}
}

View File

@@ -0,0 +1,100 @@
package com.example.library.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.library.commom.Result;
import com.example.library.entity.LendRecord;
import com.example.library.mapper.LendRecordMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/LendRecord")
public class LendRecordController {
@Resource
LendRecordMapper LendRecordMapper;
@DeleteMapping("/{isbn}")
public Result<?> delete(@PathVariable String isbn){
Map<String,Object> map = new HashMap<>();
map.put("isbn",isbn);
LendRecordMapper.deleteByMap(map);
return Result.success();
}
//删除一条记录
@PostMapping("/deleteRecord")
public Result<?> deleteRecord(@RequestBody LendRecord LendRecord){
Map<String,Object> map = new HashMap<>();
map.put("isbn",LendRecord.getIsbn());
map.put("borrownum",LendRecord.getBorrownum());
LendRecordMapper.deleteByMap(map);
return Result.success();
}
@PostMapping("/deleteRecords")
public Result<?> deleteRecords(@RequestBody List<LendRecord> LendRecords){
int len = LendRecords.size();
for(int i=0;i<len;i++) {
LendRecord curRecord = LendRecords.get(i);
Map<String,Object> map = new HashMap<>();
map.put("isbn",curRecord.getIsbn());
map.put("borrownum",curRecord.getBorrownum());
LendRecordMapper.deleteByMap(map);
}
return Result.success();
}
@PostMapping
public Result<?> save(@RequestBody LendRecord LendRecord){
LendRecordMapper.insert(LendRecord);
return Result.success();
}
@GetMapping
public Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "") String search1,
@RequestParam(defaultValue = "") String search2,
@RequestParam(defaultValue = "") String search3){
LambdaQueryWrapper<LendRecord> wrappers = Wrappers.<LendRecord>lambdaQuery();
if(StringUtils.isNotBlank(search1)){
wrappers.like(LendRecord::getIsbn,search1);
}
if(StringUtils.isNotBlank(search2)){
wrappers.like(LendRecord::getBookname,search2);
}
if(StringUtils.isNotBlank(search3)){
wrappers.like(LendRecord::getReaderId,search3);
}
Page<LendRecord> LendRecordPage =LendRecordMapper.selectPage(new Page<>(pageNum,pageSize), wrappers);
return Result.success(LendRecordPage);
}
@PutMapping("/{isbn}")
public Result<?> update(@PathVariable String isbn,@RequestBody LendRecord lendRecord){
UpdateWrapper<LendRecord> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("isbn",isbn);
LendRecord lendrecord = new LendRecord();
lendrecord.setLendTime(lendRecord.getLendTime());
lendrecord.setReturnTime(lendRecord.getReturnTime());
lendrecord.setStatus(lendRecord.getStatus());
LendRecordMapper.update(lendrecord, updateWrapper);
return Result.success();
}
@PutMapping("/{lendTime}")
public Result<?> update2(@PathVariable Date lendTime, @RequestBody LendRecord lendRecord){
UpdateWrapper<LendRecord> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("lendTime",lendTime);
LendRecord lendrecord = new LendRecord();
lendrecord.setReturnTime(lendRecord.getReturnTime());
lendrecord.setStatus(lendRecord.getStatus());
LendRecordMapper.update(lendrecord, updateWrapper);
return Result.success();
}
}

View File

@@ -0,0 +1,29 @@
package com.example.library.controller;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.library.commom.Result;
import com.example.library.entity.LendRecord;
import com.example.library.mapper.LendRecordMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/LendRecord1")
public class LendRecordController1 {
@Resource
LendRecordMapper LendRecordMapper;
@PutMapping
public Result<?> update2( @RequestBody LendRecord lendRecord){
UpdateWrapper<LendRecord> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("isbn",lendRecord.getIsbn()).eq("reader_id",lendRecord.getReaderId()).eq("borrownum",lendRecord.getBorrownum());
LendRecord lendrecord = new LendRecord();
lendrecord.setReturnTime(lendRecord.getReturnTime());
lendrecord.setStatus(lendRecord.getStatus());
LendRecordMapper.update(lendrecord, updateWrapper);
return Result.success();
}
}

View File

@@ -0,0 +1,185 @@
package com.example.library.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.library.LoginUser;
import com.example.library.commom.Result;
import com.example.library.entity.User;
import com.example.library.mapper.UserMapper;
import org.springframework.web.bind.annotation.*;
import com.example.library.utils.TokenUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
UserMapper userMapper;
@PostMapping("/register")
public Result<?> register(@RequestBody User user){
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()));
if(res != null)
{
return Result.error("-1","用户名已重复");
}
userMapper.insert(user);
return Result.success();
}
@CrossOrigin
@PostMapping("/checkusername")
public Result<?> checkusername(@RequestBody User user){
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()));
if(res == null)
{
return Result.error("-1","用户名不存在");
}
return Result.success("0");
}
@CrossOrigin
@PostMapping("/sendsms")
public Result<?> sendsms(@RequestBody User user, HttpServletRequest request){
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getPhone,user.getPhone()).eq(User::getUsername,user.getUsername()));
if(res == null)
{
return Result.error("-1","手机号错误");
}
HttpSession session = request.getSession();
session.setAttribute("code",1234);
System.out.println(session.getAttribute("code"));
return Result.success("0");
}
@CrossOrigin
@GetMapping("/checksms")
public Result<?> checksms(HttpServletRequest request){
HttpSession session = request.getSession();
String code = (String)session.getAttribute("code");
System.out.println(code);
try {
if ("1234".equals(request.getParameter("code"))) {
return Result.success("0");
} else {
return Result.error("-1", "验证码错误");
}
}
catch (Exception e) {
return Result.error("-1", "验证码错误");
}
}
@CrossOrigin
@PostMapping("/resetpassword")
public Result<?> resetpassword(@RequestBody User user){
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()));
//User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()).eq(User::getPhone,user.getPhone()));
if(res == null)
{
return Result.error("-1","用户名或手机号错误");
}
res.setPassword(user.getPassword());
userMapper.updateById(res);
return Result.success();
}
@CrossOrigin
@PostMapping("/login")
public Result<?> login(@RequestBody User user){
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()).eq(User::getPassword,user.getPassword()));
if(res == null)
{
return Result.error("-1","用户名或密码错误");
}
String token = TokenUtils.genToken(res);
res.setToken(token);
LoginUser loginuser = new LoginUser();
loginuser.addVisitCount();
return Result.success(res);
}
@PostMapping("/info")
public Result<?> userinfo(@RequestBody User user){
System.out.println(user);
User user1 = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getId,user.getId()));
System.out.println(user1);
return Result.success(user1);
}
@PostMapping
public Result<?> save(@RequestBody User user){
if(user.getPassword() == null){
user.setPassword("abc123456");
}
userMapper.insert(user);
return Result.success();
}
@PutMapping("/password")
public Result<?> update( @RequestParam Integer id,
@RequestParam String password2){
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id",id);
User user = new User();
user.setPassword(password2);
userMapper.update(user,updateWrapper);
return Result.success();
}
@PutMapping
public Result<?> password(@RequestBody User user){
userMapper.updateById(user);
return Result.success();
}
@PostMapping("/deleteBatch")
public Result<?> deleteBatch(@RequestBody List<Integer> ids){
userMapper.deleteBatchIds(ids);
return Result.success();
}
@DeleteMapping("/{id}")
public Result<?> delete(@PathVariable Long id){
userMapper.deleteById(id);
return Result.success();
}
@GetMapping
public Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "") String search){
LambdaQueryWrapper<User> wrappers = Wrappers.<User>lambdaQuery();
if(StringUtils.isNotBlank(search)){
wrappers.like(User::getNickName,search);
}
wrappers.like(User::getRole,2);
Page<User> userPage =userMapper.selectPage(new Page<>(pageNum,pageSize), wrappers);
return Result.success(userPage);
}
@GetMapping("/usersearch")
public Result<?> findPage2(@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "") String search1,
@RequestParam(defaultValue = "") String search2,
@RequestParam(defaultValue = "") String search3,
@RequestParam(defaultValue = "") String search4){
LambdaQueryWrapper<User> wrappers = Wrappers.<User>lambdaQuery();
if(StringUtils.isNotBlank(search1)){
wrappers.like(User::getId,search1);
}
if(StringUtils.isNotBlank(search2)){
wrappers.like(User::getNickName,search2);
}
if(StringUtils.isNotBlank(search3)){
wrappers.like(User::getPhone,search3);
}
if(StringUtils.isNotBlank(search4)){
wrappers.like(User::getAddress,search4);
}
wrappers.like(User::getRole,2);
Page<User> userPage =userMapper.selectPage(new Page<>(pageNum,pageSize), wrappers);
return Result.success(userPage);
}
}

View File

@@ -0,0 +1,76 @@
package com.example.library.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.library.commom.Result;
import com.example.library.entity.User;
import com.example.library.mapper.UserMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@RestController
@RequestMapping("/forget")
public class forgetController {
@Resource
UserMapper userMapper;
@CrossOrigin
@PostMapping("/checkusername")
public Result<?> checkusername(@RequestBody User user){
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()));
if(res == null)
{
return Result.error("-1","用户名不存在");
}
return Result.success("0");
}
@CrossOrigin
@PostMapping("/sendsms")
public Result<?> sendsms(@RequestBody User user, HttpServletRequest request){
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getPhone,user.getPhone()).eq(User::getUsername,user.getUsername()));
if(res == null)
{
return Result.error("-1","手机号错误");
}
HttpSession session = request.getSession();
session.setAttribute("code",1234);
System.out.println(session.getAttribute("code"));
return Result.success("0");
}
@CrossOrigin
@GetMapping("/checksms")
public Result<?> checksms(HttpServletRequest request){
HttpSession session = request.getSession();
String code = (String)session.getAttribute("code");
System.out.println(code);
try {
if ("1234".equals(request.getParameter("code"))) {
return Result.success("0");
} else {
return Result.error("-1", "验证码错误");
}
}
catch (Exception e) {
return Result.error("-1", "验证码错误");
}
}
@CrossOrigin
@PostMapping("/resetpassword")
public Result<?> resetpassword(@RequestBody User user){
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()));
//User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()).eq(User::getPhone,user.getPhone()));
if(res == null)
{
return Result.error("-1","用户名或手机号错误");
}
res.setPassword(user.getPassword());
userMapper.updateById(res);
return Result.success();
}
}

View File

@@ -0,0 +1,33 @@
package com.example.library.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@TableName("book")
@Data
public class Book {
@TableId (type = IdType.AUTO)
private Integer id;
private String isbn;
private String name;
private BigDecimal price;
private String author;
private Integer borrownum;
private String publisher;
@JsonFormat(locale="zh",timezone="GMT+8", pattern="yyyy-MM-dd")
private Date createTime;
private String status;
}

View File

@@ -0,0 +1,21 @@
package com.example.library.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@TableName("bookwithuser")
@Data
public class BookWithUser {
private Integer id;
private String isbn;
private String bookName;
private String nickName;
@JsonFormat(locale="zh",timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date lendtime;
@JsonFormat(locale="zh",timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date deadtime;
private Integer prolong;
}

View File

@@ -0,0 +1,22 @@
package com.example.library.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@TableName("lend_record")
@Data
public class LendRecord {
private Integer readerId;
private String isbn;
private String bookname;
@JsonFormat(locale="zh",timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date lendTime;
@JsonFormat(locale="zh",timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date returnTime;
private String status;
private Integer borrownum;
}

View File

@@ -0,0 +1,24 @@
package com.example.library.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@TableName("user")
@Data
public class User {
@TableId (type = IdType.AUTO)
private Integer id;
private String username;
private String nickName;
private String password;
private String sex;
private String address;
private String phone;
@TableField(exist = false) //表中没有token不会报错仍能编译运行
private String token;
private Integer role;
}

View File

@@ -0,0 +1,44 @@
package com.example.library.filter;
import com.auth0.jwt.JWT;
import com.example.library.commom.Result;
import com.example.library.entity.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AccessControlInterceptor implements HandlerInterceptor {
@Autowired
private User user;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 获取请求中的所有 Cookie
try {
String token = request.getHeader("token");
String aud = JWT.decode(token).getAudience().get(0);
Integer userId = Integer.valueOf(aud);
if (userId != null) {
return true;
}
}
catch (Exception e) {
}
response.setContentType("application/json");
ObjectMapper mapper = new ObjectMapper();
// 将 ErrorResult 对象转换为 JSON 格式
String jsonResponse = mapper.writeValueAsString(Result.noAuth());
response.getWriter().println(jsonResponse);
// 用户信息验证失败,返回 false并返回错误响应或者重定向到登录页面等操作
return false;
}
// 用户信息验证的方法,可以根据具体业务逻辑来实现
private boolean validateToken(String token) {
return user.getToken().equals(token);
}
}

View File

@@ -0,0 +1,17 @@
package com.example.library.filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*") // 允许访问的域名,可以指定多个或使用通配符 *
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法
.allowCredentials(true); // 允许传输凭证信息
}
}

View File

@@ -0,0 +1,40 @@
package com.example.library.filter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Allow-Headers", "authorization, content-type, xsrf-token");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("allowCredentials","true");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}

View File

@@ -0,0 +1,15 @@
package com.example.library.filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AccessControlInterceptor())// 添加要拦截的路径
.excludePathPatterns("/user/login").excludePathPatterns("/forget/**").excludePathPatterns("/user/register"); // 排除不需要拦截的路径
}
}

View File

@@ -0,0 +1,8 @@
package com.example.library.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.library.entity.Book;
public interface BookMapper extends BaseMapper<Book> {
}

View File

@@ -0,0 +1,8 @@
package com.example.library.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.library.entity.BookWithUser;
public interface BookWithUserMapper extends BaseMapper<BookWithUser> {
}

View File

@@ -0,0 +1,8 @@
package com.example.library.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.library.entity.LendRecord;
public interface LendRecordMapper extends BaseMapper<LendRecord> {
}

View File

@@ -0,0 +1,10 @@
package com.example.library.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.library.entity.User;
public interface UserMapper extends BaseMapper<User> {
// @Insert("INSERT INTO user_table (username, password, email) VALUES (#{username}, #{password}, #{email})")
// void insertUser(User user);
}

View File

@@ -0,0 +1,60 @@
package com.example.library.utils;
import cn.hutool.core.date.DateUtil;
import com.example.library.entity.User;
import com.example.library.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
@Slf4j
@Component
public class TokenUtils {
@Autowired
@Resource
private UserMapper userMapper;
private static UserMapper staticUserMapper;
@PostConstruct
public void init() {
staticUserMapper = userMapper;
}
/**
* 生成token
* @param user
* @return
*/
public static String genToken(User user) {
return JWT.create().withExpiresAt(DateUtil.offsetDay(new Date(), 1)).withAudience(user.getId().toString())
.sign(Algorithm.HMAC256(user.getPassword()));
}
/**
* 获取token中的用户信息
* @return
*/
public static User getUser() {
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("token");
String aud = JWT.decode(token).getAudience().get(0);
Integer userId = Integer.valueOf(aud);
return staticUserMapper.selectById(userId);
} catch (Exception e) {
log.error("解析token失败", e);
return null;
}
}
}

View File

@@ -0,0 +1,19 @@
server:
port: 9090
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot-vue?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8
username: root
password: 123456
application:
name: libirary-service
cloud:
nacos:
discovery:
server-addr: 192.168.202.220:8848

View File

@@ -0,0 +1 @@
.icon[data-v-f4e55176]{width:40px;height:40px;padding-top:5px;padding-right:10px}.icon[data-v-f5394220]{width:30px;height:30px;padding-top:5px;padding-right:10px}*{margin:0;padding:0;box-sizing:border-box}.icon{width:1em;height:1em;vertical-align:-.15em;fill:currentColor;overflow:hidden}

View File

@@ -0,0 +1 @@
.box-card[data-v-4dae75ff]{width:80%;margin-bottom:25px;margin-left:10px}.clearfix[data-v-4dae75ff]{text-align:center;font-size:15px}.text[data-v-4dae75ff]{text-align:center;font-size:24px;font-weight:700;vertical-align:super}#main[data-v-4dae75ff]{width:100%;height:450px;margin-top:20px}.icon[data-v-4dae75ff]{width:50px;height:50px;padding-top:5px;padding-right:10px}

View File

@@ -0,0 +1 @@
.ValidCode[data-v-4bf328f2]{display:flex;justify-content:center;align-items:center;cursor:pointer}.ValidCode span[data-v-4bf328f2]{display:inline-block}.login-container[data-v-70b225b5]{position:fixed;width:100%;height:100%;background:url(../img/bg2.dd39329b.svg);background-size:contain}.login-page[data-v-70b225b5]{border-radius:5px;margin:180px auto;width:350px;padding:35px 35px 15px;background:#fff;border:1px solid #eaeaea;box-shadow:0 0 25px #cac6c6}

View File

@@ -0,0 +1 @@
.avatar-uploader{border:1px dashed #d9d9d9;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader:hover{border-color:#409eff}.avatar{width:178px;height:178px;display:block}.box-card{width:60%;margin:auto;padding:20px}

View File

@@ -0,0 +1 @@
.ValidCode[data-v-4bf328f2]{display:flex;justify-content:center;align-items:center;cursor:pointer}.ValidCode span[data-v-4bf328f2]{display:inline-block}.login-container[data-v-a8e2f1f2]{position:fixed;width:100%;height:100vh;background:url(../img/bg2.dd39329b.svg);background-size:contain;overflow:hidden}.login-page[data-v-a8e2f1f2]{border-radius:5px;margin:180px auto;width:350px;padding:35px 35px 15px;background:#fff;border:1px solid #eaeaea;box-shadow:0 0 25px #cac6c6}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,33 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="100%" height="100%" viewBox="0 0 1400 800">
<rect x="1300" y="400" rx="40" ry="40" width="300" height="300" stroke="rgb(129, 201, 149)" fill="rgb(129, 201, 149)">
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="0 1450 550" to="360 1450 550" repeatCount="indefinite"/>
</rect>
<path d="M 100 350 A 150 150 0 1 1 400 350 Q400 370 380 370 L 250 370 L 120 370 Q100 370 100 350" stroke="rgb(253, 214, 99)" fill="rgb(253, 214, 99)">
<animateMotion path="M 800 -200 L 800 -300 L 800 -200" dur="20s" begin="0s" repeatCount="indefinite"/>
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="30s" type="rotate" values="0 210 530 ; -30 210 530 ; 0 210 530" keyTimes="0 ; 0.5 ; 1" repeatCount="indefinite"/>
</path>
<circle cx="200" cy="150" r="20" stroke="#1a73e8" fill="#1a73e8">
<animateMotion path="M 0 0 L 40 20 Z" dur="5s" repeatCount="indefinite"/>
</circle>
<!-- 三角形 -->
<path d="M 165 580 L 270 580 Q275 578 270 570 L 223 483 Q220 480 217 483 L 165 570 Q160 578 165 580" stroke="rgb(238, 103, 92)" fill="rgb(238, 103, 92)">
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="0 210 530" to="360 210 530" repeatCount="indefinite"/>
</path>
<circle cx="1200" cy="600" r="30" stroke="rgb(241, 243, 244)" fill="rgb(241, 243, 244)">
<animateMotion path="M 0 0 L -20 40 Z" dur="9s" repeatCount="indefinite"/>
</circle>
<path d="M 100 350 A 40 40 0 1 1 180 350 L 180 430 A 40 40 0 1 1 100 430 Z" stroke="rgb(241, 243, 244)" fill="rgb(241, 243, 244)">
<animateMotion path="M 140 390 L 180 360 L 140 390" dur="20s" begin="0s" repeatCount="indefinite"/>
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="30s" type="rotate" values="0 140 390; -60 140 390; 0 140 390" keyTimes="0 ; 0.5 ; 1" repeatCount="indefinite"/>
</path>
<rect x="400" y="600" rx="40" ry="40" width="100" height="100" stroke="rgb(129, 201, 149)" fill="rgb(129, 201, 149)">
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="-30 550 750" to="330 550 750" repeatCount="indefinite"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>vue_demo</title><link href="/css/chunk-0ef1ccea.91552112.css" rel="prefetch"><link href="/css/chunk-1d2b6d9d.750ab8fd.css" rel="prefetch"><link href="/css/chunk-1e6a6472.a9697564.css" rel="prefetch"><link href="/css/chunk-752ac4fb.e53c3c2c.css" rel="prefetch"><link href="/js/chunk-0be195b0.11a9a989.js" rel="prefetch"><link href="/js/chunk-0ef1ccea.8151085a.js" rel="prefetch"><link href="/js/chunk-1d2b6d9d.13081618.js" rel="prefetch"><link href="/js/chunk-1e6a6472.ed80c125.js" rel="prefetch"><link href="/js/chunk-25f25a31.25ed3d91.js" rel="prefetch"><link href="/js/chunk-2d0c0df2.9b822a3f.js" rel="prefetch"><link href="/js/chunk-2d0c1074.8dbc50ec.js" rel="prefetch"><link href="/js/chunk-33419c76.697ed836.js" rel="prefetch"><link href="/js/chunk-6cd47659.348c5279.js" rel="prefetch"><link href="/js/chunk-6fecba8e.e1b4f3ca.js" rel="prefetch"><link href="/js/chunk-752ac4fb.b6d0ae67.js" rel="prefetch"><link href="/css/app.90e92dc6.css" rel="preload" as="style"><link href="/css/chunk-vendors.041c0013.css" rel="preload" as="style"><link href="/js/app.3d87220e.js" rel="preload" as="script"><link href="/js/chunk-vendors.c2943193.js" rel="preload" as="script"><link href="/css/chunk-vendors.041c0013.css" rel="stylesheet"><link href="/css/app.90e92dc6.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but vue_demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.c2943193.js"></script><script src="/js/app.3d87220e.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-1e6a6472"],{c714:function(e,t,o){},ce40:function(e,t,o){"use strict";o.r(t);var n=o("7a23"),r=Object(n["createElementVNode"])("h2",{style:{padding:"30px"}},"个人信息",-1),c={key:0,style:{margin:"5px"}},a={key:1,style:{margin:"5px"}},l=Object(n["createTextVNode"])("男"),u=Object(n["createTextVNode"])("女"),d={style:{"text-align":"center"}},i=Object(n["createTextVNode"])("保存");function f(e,t,o,f,m,s){var b=Object(n["resolveComponent"])("el-input"),O=Object(n["resolveComponent"])("el-form-item"),j=Object(n["resolveComponent"])("el-radio"),p=Object(n["resolveComponent"])("el-form"),V=Object(n["resolveComponent"])("el-button"),h=Object(n["resolveComponent"])("el-card");return Object(n["openBlock"])(),Object(n["createElementBlock"])("div",null,[Object(n["createVNode"])(h,{style:{width:"40%","margin-left":"120px","margin-top":"40px"}},{default:Object(n["withCtx"])((function(){return[r,Object(n["createVNode"])(p,{model:m.form,ref:"form","label-width":"80px"},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(O,{label:"用户名"},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(b,{style:{width:"80%"},modelValue:m.form.username,"onUpdate:modelValue":t[0]||(t[0]=function(e){return m.form.username=e}),disabled:""},null,8,["modelValue"])]})),_:1}),Object(n["createVNode"])(O,{label:"姓名"},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(b,{style:{width:"80%"},modelValue:m.form.nickName,"onUpdate:modelValue":t[1]||(t[1]=function(e){return m.form.nickName=e})},null,8,["modelValue"])]})),_:1}),Object(n["createVNode"])(O,{label:"权限"},{default:Object(n["withCtx"])((function(){return[1==m.form.role?(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",c,"管理员")):Object(n["createCommentVNode"])("",!0),2==m.form.role?(Object(n["openBlock"])(),Object(n["createElementBlock"])("span",a,"读者")):Object(n["createCommentVNode"])("",!0)]})),_:1}),Object(n["createVNode"])(O,{label:"电话号码"},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(b,{style:{width:"80%"},modelValue:m.form.phone,"onUpdate:modelValue":t[2]||(t[2]=function(e){return m.form.phone=e})},null,8,["modelValue"])]})),_:1}),Object(n["createVNode"])(O,{label:"性别"},{default:Object(n["withCtx"])((function(){return[Object(n["createElementVNode"])("div",null,[Object(n["createVNode"])(j,{modelValue:m.form.sex,"onUpdate:modelValue":t[3]||(t[3]=function(e){return m.form.sex=e}),label:"男"},{default:Object(n["withCtx"])((function(){return[l]})),_:1},8,["modelValue"]),Object(n["createVNode"])(j,{modelValue:m.form.sex,"onUpdate:modelValue":t[4]||(t[4]=function(e){return m.form.sex=e}),label:"女"},{default:Object(n["withCtx"])((function(){return[u]})),_:1},8,["modelValue"])])]})),_:1}),Object(n["createVNode"])(O,{label:"地址"},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(b,{type:"textarea",style:{width:"80%"},modelValue:m.form.address,"onUpdate:modelValue":t[5]||(t[5]=function(e){return m.form.address=e})},null,8,["modelValue"])]})),_:1})]})),_:1},8,["model"]),Object(n["createElementVNode"])("div",d,[Object(n["createVNode"])(V,{type:"primary",onClick:s.update},{default:Object(n["withCtx"])((function(){return[i]})),_:1},8,["onClick"])])]})),_:1})])}o("e9c4");var m=o("b775"),s=o("3ef4"),b={name:"Person",data:function(){return{form:{}}},created:function(){var e=sessionStorage.getItem("user")||"{}";this.form=JSON.parse(e)},methods:{update:function(){var e=this;m["a"].put("/user",this.form).then((function(t){console.log(t),"0"===t.code?(s["a"].success("更新成功"),sessionStorage.setItem("user",JSON.stringify(e.form)),e.$emit("userInfo")):s["a"].error(t.msg)}))}}},O=(o("fe6f"),o("6b0d")),j=o.n(O);const p=j()(b,[["render",f]]);t["default"]=p},e9c4:function(e,t,o){var n=o("23e7"),r=o("da84"),c=o("d066"),a=o("2ba4"),l=o("e330"),u=o("d039"),d=r.Array,i=c("JSON","stringify"),f=l(/./.exec),m=l("".charAt),s=l("".charCodeAt),b=l("".replace),O=l(1..toString),j=/[\uD800-\uDFFF]/g,p=/^[\uD800-\uDBFF]$/,V=/^[\uDC00-\uDFFF]$/,h=function(e,t,o){var n=m(o,t-1),r=m(o,t+1);return f(p,e)&&!f(V,r)||f(V,e)&&!f(p,n)?"\\u"+O(s(e,0),16):e},N=u((function(){return'"\\udf06\\ud834"'!==i("\udf06\ud834")||'"\\udead"'!==i("\udead")}));i&&n({target:"JSON",stat:!0,forced:N},{stringify:function(e,t,o){for(var n=0,r=arguments.length,c=d(r);n<r;n++)c[n]=arguments[n];var l=a(i,null,c);return"string"==typeof l?b(l,j,h):l}})},fe6f:function(e,t,o){"use strict";o("c714")}}]);
//# sourceMappingURL=chunk-1e6a6472.ed80c125.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0c1074"],{"43fe":function(e,t,r){"use strict";r.r(t);var o=r("7a23"),n=Object(o["createTextVNode"])("提交"),a=Object(o["createTextVNode"])("重置");function s(e,t,r,s,c,u){var l=Object(o["resolveComponent"])("el-input"),d=Object(o["resolveComponent"])("el-form-item"),i=Object(o["resolveComponent"])("el-button"),f=Object(o["resolveComponent"])("el-form"),p=Object(o["resolveComponent"])("el-card");return Object(o["openBlock"])(),Object(o["createElementBlock"])("div",null,[Object(o["createVNode"])(p,{style:{width:"40%","margin-left":"120px","margin-top":"40px"}},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(f,{ref:"form",model:c.form,"status-icon":"",rules:c.rules,"label-width":"100px",class:"demo-ruleForm"},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(d,{label:"老密码",prop:"password2"},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(l,{modelValue:c.form.password2,"onUpdate:modelValue":t[0]||(t[0]=function(e){return c.form.password2=e}),type:"password",autocomplete:"off"},null,8,["modelValue"])]})),_:1}),Object(o["createVNode"])(d,{label:"新密码",prop:"password"},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(l,{modelValue:c.form2.password,"onUpdate:modelValue":t[1]||(t[1]=function(e){return c.form2.password=e}),type:"password",autocomplete:"off"},null,8,["modelValue"])]})),_:1}),Object(o["createVNode"])(d,{label:"确认新密码",prop:"checkpassword"},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(l,{modelValue:c.form.checkpassword,"onUpdate:modelValue":t[2]||(t[2]=function(e){return c.form.checkpassword=e}),type:"password",autocomplete:"off"},null,8,["modelValue"])]})),_:1}),Object(o["createVNode"])(d,null,{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(i,{type:"primary",onClick:u.submitForm,style:{"text-align":"center"}},{default:Object(o["withCtx"])((function(){return[n]})),_:1},8,["onClick"]),Object(o["createVNode"])(i,{onClick:t[3]||(t[3]=function(e){return u.resetForm("form")}),style:{"text-align":"center"}},{default:Object(o["withCtx"])((function(){return[a]})),_:1})]})),_:1})]})),_:1},8,["model","rules"])]})),_:1})])}var c=r("b775"),u=r("3ef4"),l={name:"Password",data:function(){var e=this,t=function(t,r,o){""==r?o(new Error("请输入老密码")):(e.form.password2!==e.form.truepassword&&o(new Error("密码错误")),o())},r=function(e,t,r){""===t?r(new Error("请输入新密码")):r()},o=function(t,r,o){""===r?o(new Error("请再次输入密码")):r!==e.form2.password?o(new Error("两次输入密码不匹配")):o()};return{form:{password2:"",checkpassword:"",truepassword:""},form2:{password:"",id:0},rules:{password:[{validator:r,trigger:"blur",required:!0}],checkpassword:[{validator:o,trigger:"blur",required:!0}],password2:[{validator:t,trigger:"blur",required:!0}]}}},created:function(){var e=JSON.parse(sessionStorage.getItem("user"));this.form.truepassword=e.password,this.form2.id=e.id},methods:{submitForm:function(){var e=this;this.$refs["form"].validate((function(t){t&&c["a"].put("/user",e.form2).then((function(t){0==t.code?(u["a"].success("密码修改成功,请重新登录"),sessionStorage.removeItem("user"),e.$router.push("/login")):u["a"].error(t.msg)}))}))},resetForm:function(e){this.$refs[e].resetFields()}}},d=r("6b0d"),i=r.n(d);const f=i()(l,[["render",s]]);t["default"]=f}}]);
//# sourceMappingURL=chunk-2d0c1074.8dbc50ec.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

117
pom.xml Normal file
View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>security-api-demo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>gateway</module>
<module>common</module>
<module>user</module>
<module>library</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<!--spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<!--commons-langs-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- java8 环境-->
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

46
user/pom.xml Normal file
View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>security-api-demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--spring cloud alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!--依赖common-->
<dependency>
<groupId>org.example</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,25 @@
package com.demo.user;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Description:
* @Author: rosh
* @Date: 2021/10/24 23:59
* //
*/
@SpringBootApplication
@EnableDiscoveryClient
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class);
}
}

View File

@@ -0,0 +1,33 @@
package com.demo.user.controller;
import com.alibaba.fastjson.JSONObject;
import com.demo.user.form.UserForm;
import com.demo.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @Description:
* @Author: rosh
* @Date: 2021/10/25 22:11
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/login")
public UserForm login(@RequestBody UserForm userForm) {
return userForm;
}
@GetMapping("/detail")
public JSONObject detail(@RequestParam("id") Long id) {
return userService.detail(id);
}
}

View File

@@ -0,0 +1,21 @@
package com.demo.user.form;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Description:
* @Author: rosh
* @Date: 2021/10/25 23:55
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserForm {
private String username;
private String password;
}

View File

@@ -0,0 +1,51 @@
package com.demo.user.service;
import com.alibaba.fastjson.JSONObject;
import com.demo.user.form.UserForm;
import com.demo.utils.TokenUtils;
import org.springframework.stereotype.Service;
/**
* @Description:
* @Author: rosh
* @Date: 2021/10/25 22:21
*/
@Service
public class UserService {
private static final String USERNAME = "admin";
private static final String PASSWORD = "123456";
private static final Long USER_ID = 1L;
/**
* 模拟 登录 username = admin, password =123456,user_id 1L 登录成功 返回token
*/
public String login(UserForm userForm) {
String username = userForm.getUsername();
String password = userForm.getPassword();
if (USERNAME.equals(username) && PASSWORD.equals(password)) {
JSONObject userInfo = new JSONObject();
userInfo.put("username", USERNAME);
userInfo.put("password", PASSWORD);
userInfo.put("userId", USER_ID);
return TokenUtils.createToken(userInfo.toJSONString());
}
return "账号密码不正确";
}
public JSONObject detail(Long id) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", id);
jsonObject.put("name", "admin");
return jsonObject;
}
}

View File

@@ -0,0 +1,13 @@
server:
port: 8000
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: 192.168.202.219:8849
redis:
port: 6379
host: 127.0.0.1

View File

@@ -0,0 +1,59 @@
package com.rosh;
import com.alibaba.fastjson.JSONObject;
import com.demo.utils.RSAUtils;
import org.junit.Test;
import java.util.Map;
/**
* @Description:
* @Author: rosh
* @Date: 2021/10/25 22:30
*/
public class RsaTest {
/**
* 用测试生成的公钥,私钥赋值
*/
private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCFtTlL61IqIGd+fRLUhJ0MjsqFXFJswCohJ45m51WvbxDPRP3gllW0WChk74D5JEOpMDSWo4C7RfoGlBRNW7kQ6qYGukYZ5jgYpzoT0+gp3on96fQXEyQJysv9xiTPIdmSXXVVj1HAOJw29RbzxIVKUSzzPXvEtXRTtCC1+wkAJQIDAQAB";
private static final String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIW1OUvrUiogZ359EtSEnQyOyoVcUmzAKiEnjmbnVa9vEM9E/eCWVbRYKGTvgPkkQ6kwNJajgLtF+gaUFE1buRDqpga6RhnmOBinOhPT6Cneif3p9BcTJAnKy/3GJM8h2ZJddVWPUcA4nDb1FvPEhUpRLPM9e8S1dFO0ILX7CQAlAgMBAAECgYBC4amtbiKFa/wY61tV7pfYRjzLhKi+OUlZmD3E/4Z+4KGZ7DrJ8qkgMtDR3HO5LAikQrare1HTW2d7juqw32ascu+uDObf4yrYNKin+ZDLUYvIDfLhThPxnZJwQ/trdtfxO3VM//XbwZacmwYbAsYW/3QPUXwwOPAgbC2oth8kqQJBANKLyXcdjZx4cwJVl7xNeC847su8y6bPpcBASsaQloCIPiNBIg1h76dpfEGIQBYWJWbBsxtHe/MhOmz7fNFDS2sCQQCiktYZR0dZNH4eNX329LoRuBiltpr9tf36rVOlKr1GSHkLYEHF2qtyXV2mdrY8ZWpvuo3qm1oSLaqmop2rN9avAkBHk85B+IIUF77BpGeZVJzvMOO9z8lMRHuNCE5jgvQnbinxwkrZUdovh+T+QlvHJnBApslFFOBGn51FP5oHamFRAkEAmwZmPsinkrrpoKjlqz6GyCrC5hKRDWoj/IyXfKKaxpCJTH3HeoIghvfdO8Vr1X/n1Q8SESt+4mLFngznSMQAZQJBAJx07bCFYbA2IocfFV5LTEYTIiUeKdue2NP2yWqZ/+tB5H7jNwQTJmX1mn0W/sZm4+nJM7SjfETpNZhH49+rV6U=";
/**
* 生成公钥私钥
*/
@Test
public void generateRsaKey() {
Map<String, String> map = RSAUtils.generateRasKey();
System.out.println("随机生成的公钥为:" + map.get(RSAUtils.PUBLIC_KEY));
System.out.println("随机生成的私钥为:" + map.get(RSAUtils.PRIVATE_KEY));
}
/**
* 加密: Yeidauky/iN1/whevov2+ntzXJKAp2AHfESu5ixnDqH5iB7ww+TcfqJpDfkPHfb12Y0sVXw0gBHNJ4inkh7l2/SJBze3pKQU/mg3oyDokTia3JZIs+e80/iJcSfN+yA1JaqY+eJPYiBiOGAF2S6x0ynvJg/Wj0fwp2Tq3PDzRMo=
*/
@Test
public void testEncrypt() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("username", "rosh");
jsonObject.put("password", "123456");
String str = jsonObject.toJSONString();
String encrypt = RSAUtils.encrypt(str, PUBLIC_KEY);
System.out.println(encrypt);
}
@Test
public void testDecrypt() {
String decrypt = RSAUtils.decrypt("Xt2eKETPNqCLjTjaXOx2qfotfbPRGjLsY/XqoQoQfOc/WjVJ4/QgV2CyUug4YTy0scPA0R7h91UbVDViOMoA2YFJ7DAhvrUxDBK9sw0Fn0bMkWHErSHF3c7JTz6PKYz3ZHou2+incRbY/bTu13+SzN15DgaxWV1VfOWG+DU9L6M=",
PRIVATE_KEY);
System.out.println(decrypt);
}
}