Compare commits
3 Commits
6a2f12b353
...
159e5ae34f
Author | SHA1 | Date | |
---|---|---|---|
159e5ae34f | |||
36a1ceb23e | |||
fae7339c84 |
@ -6,7 +6,21 @@ plugins {
|
||||
}
|
||||
|
||||
group = "org.mmga"
|
||||
version = "0.0.5-SNAPSHOT"
|
||||
version = "0.0.5"
|
||||
tasks.compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
tasks.javadoc {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
tasks.register<Jar>("javadocJar") {
|
||||
archiveClassifier.set("javadoc")
|
||||
from(tasks.named("javadoc"))
|
||||
}
|
||||
tasks.register<Jar>("sourcesJar") {
|
||||
archiveClassifier.set("sources")
|
||||
from(sourceSets.main.get().allSource)
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
@ -71,6 +85,9 @@ publishing {
|
||||
groupId = "org.mmga"
|
||||
artifactId = "make-minecraft-great-again-spring-boot-starter"
|
||||
version = version
|
||||
|
||||
artifact(tasks.named("javadocJar"))
|
||||
artifact(tasks.named("sourcesJar"))
|
||||
pom {
|
||||
name.set("MakeMinecraftGreatAgainSpringBootStarter")
|
||||
description.set("A Spring Boot Starter for mmga team.")
|
||||
|
@ -6,9 +6,9 @@ import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.mmga.spring.boot.starter.componet.JwtUtils;
|
||||
import org.mmga.spring.boot.starter.entities.Result;
|
||||
import org.mmga.spring.boot.starter.exception.AuthorizationException;
|
||||
import org.mmga.spring.boot.starter.exception.ServerException;
|
||||
import org.mmga.spring.boot.starter.interfaces.IdHolder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.mmga.spring.boot.starter.properties.AuthorizationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
@ -19,6 +19,8 @@ import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
@RequiredArgsConstructor
|
||||
public class AuthMappingHandler {
|
||||
private final JwtUtils jwtUtils;
|
||||
private final AuthorizationProperties properties;
|
||||
|
||||
|
||||
public Long getUserIdFromResponse(Object response) {
|
||||
if (response instanceof Result<?> result) {
|
||||
@ -50,9 +52,10 @@ public class AuthMappingHandler {
|
||||
if (returnValue instanceof Result<?> result) {
|
||||
if (!result.isOK()) return;
|
||||
}
|
||||
throw new AuthorizationException(Result.failed(HttpStatus.INTERNAL_SERVER_ERROR, "登录失败,服务端未找到可用的用户id"));
|
||||
throw new ServerException("登录失败,服务端未找到可用的用户id");
|
||||
}
|
||||
response.setHeader("Add-Authorization", token);
|
||||
String setAuthorizationHeader = properties.getSetAuthorizationHeader();
|
||||
response.setHeader(setAuthorizationHeader, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,13 +7,38 @@ import org.springframework.web.context.request.WebRequest;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 验证处理类
|
||||
* @param <T> 用户信息类型
|
||||
*/
|
||||
public interface AuthorizationHandler<T> {
|
||||
/**
|
||||
* 进行验证
|
||||
* @param token token
|
||||
* @param ann 注解
|
||||
* @return 若登录失败则返回空Optional或抛出AuthorizationException异常,若登录成功则返回用户信息
|
||||
*/
|
||||
Optional<T> auth(String token, Annotation ann);
|
||||
|
||||
|
||||
/**
|
||||
* 对于WebRequest的token处理方式
|
||||
* @param request 原始请求
|
||||
* @param ann 注解
|
||||
* @return 若登录失败则返回空Optional或抛出AuthorizationException异常,若登录成功则返回用户信息
|
||||
* @throws AuthorizationException 当验证失败时可抛出
|
||||
*/
|
||||
default Optional<T> auth(WebRequest request, Annotation ann) throws AuthorizationException {
|
||||
return auth(request.getHeader("Authorization"), ann);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对于HttpServletRequest的token处理方式
|
||||
* @param request 原始请求
|
||||
* @param ann 注解
|
||||
* @return 若登录失败则返回空Optional或抛出AuthorizationException异常,若登录成功则返回用户信息
|
||||
* @throws AuthorizationException 当验证失败时可抛出
|
||||
*/
|
||||
default Optional<T> auth(HttpServletRequest request, Annotation ann) throws AuthorizationException {
|
||||
return auth(request.getHeader("Authorization"), ann);
|
||||
}
|
||||
|
@ -2,8 +2,21 @@ package org.mmga.spring.boot.starter.componet;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* jwt处理接口
|
||||
*/
|
||||
public interface JwtUtils {
|
||||
/**
|
||||
* 通过用户ID生成jwt
|
||||
* @param uid 用户ID
|
||||
* @return jwtToken
|
||||
*/
|
||||
String createToken(long uid);
|
||||
|
||||
/**
|
||||
* 验证token
|
||||
* @param token token
|
||||
* @return 若成功则返回用户ID,否则返回空Optional
|
||||
*/
|
||||
Optional<Long> verifyToken(String token);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package org.mmga.spring.boot.starter.configuration;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.mmga.spring.boot.starter.properties.AuthorizationProperties;
|
||||
import org.mmga.spring.boot.starter.properties.Env;
|
||||
import org.mmga.spring.boot.starter.properties.MainProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@ -11,9 +12,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@EnableConfigurationProperties({MainProperties.class})
|
||||
@EnableConfigurationProperties({MainProperties.class, AuthorizationProperties.class})
|
||||
public class CorsConfiguration implements WebMvcConfigurer {
|
||||
private final MainProperties mainProperties;
|
||||
private final AuthorizationProperties properties;
|
||||
|
||||
|
||||
@Override
|
||||
@ -21,7 +23,7 @@ public class CorsConfiguration implements WebMvcConfigurer {
|
||||
if (mainProperties.getEnv().equals(Env.DEV)) {
|
||||
registry.addMapping("/**") //允许所有路径进行CORS
|
||||
.allowedHeaders("*")
|
||||
.exposedHeaders("Add-Authorization")
|
||||
.exposedHeaders(properties.getSetAuthorizationHeader())
|
||||
.allowedMethods("*"); //允许所有请求方式
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
package org.mmga.spring.boot.starter.configuration;
|
||||
|
||||
import org.mmga.spring.boot.starter.entities.Result;
|
||||
import org.mmga.spring.boot.starter.exception.AuthorizationException;
|
||||
import org.mmga.spring.boot.starter.exception.BaseResultException;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
@ControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
@ExceptionHandler(AuthorizationException.class)
|
||||
public ResponseEntity<Result<Void>> handleAuthorizationException(AuthorizationException e) {
|
||||
Result<Void> result = e.getResult();
|
||||
@ExceptionHandler(BaseResultException.class)
|
||||
public ResponseEntity<Result<?>> handleAuthorizationException(BaseResultException e) {
|
||||
Result<?> result = e.getResult();
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
}
|
@ -6,6 +6,10 @@ import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页数据
|
||||
* @param <T> 数据类型
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "分页数据")
|
||||
@AllArgsConstructor
|
||||
|
@ -1,14 +1,29 @@
|
||||
package org.mmga.spring.boot.starter.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.mmga.spring.boot.starter.entities.Result;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
@Getter
|
||||
public class AuthorizationException extends RuntimeException {
|
||||
private final Result<Void> result;
|
||||
/**
|
||||
* 登录失败错误
|
||||
*/
|
||||
public class AuthorizationException extends BaseResultException {
|
||||
|
||||
/**
|
||||
* @deprecated 此方法不安全
|
||||
* @see #AuthorizationException(String)
|
||||
* @param result 使用result
|
||||
*/
|
||||
@Deprecated
|
||||
public AuthorizationException(Result<Void> result) {
|
||||
super(result.getMsg());
|
||||
this.result = result;
|
||||
super(result);
|
||||
super.setResult(result);
|
||||
}
|
||||
|
||||
/**
|
||||
将会发送401状态码
|
||||
* @param message 消息
|
||||
*/
|
||||
public AuthorizationException(String message) {
|
||||
super(Result.failed(HttpStatus.UNAUTHORIZED, message));
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package org.mmga.spring.boot.starter.exception;
|
||||
|
||||
import lombok.*;
|
||||
import org.mmga.spring.boot.starter.entities.Result;
|
||||
|
||||
@Getter
|
||||
@Setter(AccessLevel.PROTECTED)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@ToString
|
||||
@AllArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public abstract class BaseResultException extends RuntimeException {
|
||||
private Result<?> result;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.mmga.spring.boot.starter.exception;
|
||||
|
||||
import org.mmga.spring.boot.starter.entities.Result;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* 异常类
|
||||
*/
|
||||
public class ResultException extends BaseResultException {
|
||||
/**
|
||||
* @param httpStatus http状态码
|
||||
* @param message 消息
|
||||
*/
|
||||
public ResultException(HttpStatus httpStatus, String message) {
|
||||
super(Result.failed(httpStatus, message));
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.mmga.spring.boot.starter.exception;
|
||||
|
||||
import org.mmga.spring.boot.starter.entities.Result;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* 服务端错误(500 Internal Server Error)
|
||||
*/
|
||||
public class ServerException extends BaseResultException {
|
||||
/**
|
||||
* 将会返回500
|
||||
* @param message 消息
|
||||
*/
|
||||
public ServerException(String message) {
|
||||
super(Result.failed(HttpStatus.INTERNAL_SERVER_ERROR, message));
|
||||
}
|
||||
}
|
@ -1,5 +1,12 @@
|
||||
package org.mmga.spring.boot.starter.interfaces;
|
||||
|
||||
/**
|
||||
* id拥有者容器
|
||||
*/
|
||||
public interface IdHolder {
|
||||
/**
|
||||
* 获取ID
|
||||
* @return ID
|
||||
*/
|
||||
Long getId();
|
||||
}
|
||||
|
@ -5,12 +5,34 @@ import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
|
||||
/**
|
||||
* 用户验证相关配置
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "mmga.auth")
|
||||
@Data
|
||||
public class AuthorizationProperties {
|
||||
/**
|
||||
* jwt使用的hmac密钥(RANDOM为随机密钥)
|
||||
*/
|
||||
private String hmacKey = "RANDOM";
|
||||
/**
|
||||
* 设置token所使用的请求头
|
||||
*/
|
||||
private String setAuthorizationHeader = "Add-Authorization";
|
||||
/**
|
||||
* token有效期
|
||||
*/
|
||||
private int tokenLifeTimeHour = 24 * 5;
|
||||
/**
|
||||
* 密钥的存储方式
|
||||
*/
|
||||
private ECKeySave keySave = ECKeySave.MEMORY;
|
||||
|
||||
/**
|
||||
* 密钥的存储文件名(当keySave为DISK时不可为空)
|
||||
* @see #keySave
|
||||
* @see ECKeySave
|
||||
*/
|
||||
@Nullable
|
||||
private String keySaveFilename = null;
|
||||
}
|
||||
|
@ -3,9 +3,18 @@ package org.mmga.spring.boot.starter.properties;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 文档相关配置
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "mmga.docs")
|
||||
@Data
|
||||
public class DocsProperties {
|
||||
/**
|
||||
* 文档标题
|
||||
*/
|
||||
private String title = "API文档";
|
||||
/**
|
||||
* 文档详情
|
||||
*/
|
||||
private String description = "";
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
package org.mmga.spring.boot.starter.properties;
|
||||
|
||||
public enum Env {
|
||||
PROD, DEV
|
||||
/**
|
||||
* 生产环境
|
||||
*/
|
||||
PROD,
|
||||
/**
|
||||
* 开发环境
|
||||
*/
|
||||
DEV
|
||||
}
|
||||
|
@ -6,5 +6,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@ConfigurationProperties(prefix = "mmga")
|
||||
@Data
|
||||
public class MainProperties {
|
||||
/**
|
||||
* 环境类型
|
||||
*/
|
||||
private Env env = Env.DEV;
|
||||
}
|
||||
|
@ -3,10 +3,8 @@ package org.mmga.spring.boot.starter.utils;
|
||||
import jakarta.annotation.Nullable;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.mmga.spring.boot.starter.componet.AuthorizationHandler;
|
||||
import org.mmga.spring.boot.starter.entities.Result;
|
||||
import org.mmga.spring.boot.starter.exception.AuthorizationException;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
@ -35,7 +33,7 @@ public class AuthorizationArgumentResolver implements HandlerMethodArgumentResol
|
||||
assert parameterAnnotation != null;
|
||||
Optional<?> auth = this.handler.auth(webRequest, parameterAnnotation);
|
||||
if (auth.isEmpty()) {
|
||||
throw new AuthorizationException(Result.failed(HttpStatus.UNAUTHORIZED, "缺少token"));
|
||||
throw new AuthorizationException("缺少token");
|
||||
}
|
||||
return auth.get();
|
||||
}
|
||||
|
@ -4,9 +4,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.mmga.spring.boot.starter.componet.AuthorizationHandler;
|
||||
import org.mmga.spring.boot.starter.entities.Result;
|
||||
import org.mmga.spring.boot.starter.exception.AuthorizationException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
@ -30,7 +28,7 @@ public class AuthorizationHandlerInterceptor implements HandlerInterceptor {
|
||||
Annotation annotation = method.getMethodAnnotation(authAnnotation);
|
||||
Optional<?> auth = this.handler.auth(request, annotation);
|
||||
if (auth.isEmpty()) {
|
||||
throw new AuthorizationException(Result.failed(HttpStatus.UNAUTHORIZED, "缺少token"));
|
||||
throw new AuthorizationException("缺少token");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user