add custom session, permission

This commit is contained in:
2021-11-14 11:39:36 +08:00
parent b1577a60e1
commit 110a5d9138
9 changed files with 245 additions and 0 deletions

View File

@@ -1,5 +1,7 @@
package me.hatter.sample.common;
import me.hatter.sample.common.interceptor.CustomHandlerInterceptorAdapter;
import me.hatter.sample.common.resolver.CustomSessionArgumentResolver;
import me.hatter.sample.common.resolver.SystemTimeArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@@ -14,8 +16,20 @@ public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
SystemTimeArgumentResolver systemTimeArgumentResolver;
@Autowired
CustomSessionArgumentResolver customSessionArgumentResolver;
@Autowired
CustomHandlerInterceptorAdapter customHandlerInterceptorAdapter;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(systemTimeArgumentResolver);
argumentResolvers.add(customSessionArgumentResolver);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customHandlerInterceptorAdapter);
}
}

View File

@@ -0,0 +1,9 @@
package me.hatter.sample.common.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Permission {
}

View File

@@ -0,0 +1,32 @@
package me.hatter.sample.common.handler;
import com.alibaba.fastjson.JSON;
import me.hatter.sample.common.message.ErrorMessageException;
import me.hatter.tools.commons.exception.ExceptionUtil;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ResponseBody
// @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "internal error")
@ExceptionHandler(Throwable.class)
public void handleException(HttpServletResponse response, Throwable t) throws IOException {
if (t instanceof ErrorMessageException) {
response.setStatus(((ErrorMessageException) t).getStatusCode());
response.getWriter().write(JSON.toJSONString(((ErrorMessageException) t).getErrorMessage(), true));
} else {
final Map<String, Object> result = new LinkedHashMap<>();
result.put("stacktrace", ExceptionUtil.printStackTrace(t));
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write(JSON.toJSONString(result, true));
}
}
}

View File

@@ -0,0 +1,42 @@
package me.hatter.sample.common.interceptor;
import me.hatter.sample.common.annotation.Permission;
import me.hatter.sample.common.message.ErrorMessage;
import org.springframework.boot.autoconfigure.web.BasicErrorController;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class CustomHandlerInterceptorAdapter extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("[CustomHandlerInterceptorAdapter] " + handler.getClass());
if (!(handler instanceof HandlerMethod)) {
throw new IllegalArgumentException("Not supported handler: " + handler.getClass());
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
// ignore error controller
if (handlerMethod.getMethod().getDeclaringClass().equals(BasicErrorController.class)) {
return true;
}
// Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
//
// RequestAttributes requestAttributes = new ServletRequestAttributes(request);
// DefaultErrorAttributes errorAttributes = new DefaultErrorAttributes();
// Map<String, Object> attributes = errorAttributes.getErrorAttributes(requestAttributes, true);
Permission p = handlerMethod.getMethodAnnotation(Permission.class);
if (p == null) {
throw new ErrorMessage("permission_denied",
"No permission: " + request.getRequestURI()
).ex(HttpServletResponse.SC_FORBIDDEN);
}
return false;
}
}

View File

@@ -0,0 +1,34 @@
package me.hatter.sample.common.message;
public class ErrorMessage {
private String error;
private String error_description;
public ErrorMessage() {
}
public ErrorMessage(String error, String error_description) {
this.error = error;
this.error_description = error_description;
}
public ErrorMessageException ex(int statusCode) {
return new ErrorMessageException(statusCode, this);
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public String getError_description() {
return error_description;
}
public void setError_description(String error_description) {
this.error_description = error_description;
}
}

View File

@@ -0,0 +1,24 @@
package me.hatter.sample.common.message;
public class ErrorMessageException extends RuntimeException {
private final int statusCode;
private final ErrorMessage errorMessage;
public ErrorMessageException(int statusCode, ErrorMessage errorMessage) {
this.statusCode = statusCode;
this.errorMessage = errorMessage;
}
public int getStatusCode() {
return statusCode;
}
public ErrorMessage getErrorMessage() {
return errorMessage;
}
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}

View File

@@ -0,0 +1,38 @@
package me.hatter.sample.common.resolver;
import me.hatter.sample.common.session.CustomSession;
import me.hatter.tools.commons.security.random.RandomTool;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.util.WebUtils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
@Component
public class CustomSessionArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(CustomSession.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
final HttpServletRequest httpServletRequest = (HttpServletRequest) webRequest.getNativeRequest();
final HttpServletResponse httpServletResponse = (HttpServletResponse) webRequest.getNativeResponse();
Cookie cookie = WebUtils.getCookie(httpServletRequest, "hatter_session_id");
if (cookie == null) {
cookie = new Cookie("hatter_session_id", RandomTool.secureRandom().nextBytes(64).asBase58());
cookie.setPath("/");
cookie.setHttpOnly(true);
httpServletResponse.addCookie(cookie);
}
final String prefix = cookie.getValue();
return new CustomSession(prefix);
}
}

View File

@@ -0,0 +1,25 @@
package me.hatter.sample.common.session;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class CustomSession {
private static final ConcurrentMap<String, Object> cache = new ConcurrentHashMap<>();
private final String prefix;
public CustomSession(String prefix) {
this.prefix = prefix;
}
public void put(String key, Object value) {
cache.put(prefix + ":" + key, value);
}
public Object get(String key) {
return cache.get(prefix + ":" + key);
}
public String getSessionId() {
return prefix;
}
}

View File

@@ -1,6 +1,8 @@
package me.hatter.sample.web.controller;
import me.hatter.sample.common.annotation.Permission;
import me.hatter.sample.common.annotation.SystemTime;
import me.hatter.sample.common.session.CustomSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -9,9 +11,34 @@ import java.util.Date;
@RestController
public class SampleController {
@Permission
@GetMapping("/")
public String home(
@SystemTime Date time) {
return "Hello, World: " + time;
}
@Permission
@GetMapping("/exception")
public String exception() {
throw new RuntimeException("error");
}
@GetMapping("/nopermission")
public String noPermission() {
return "Hello, World!";
}
@Permission
@GetMapping("/count")
public String count(CustomSession session) {
final Object c = session.get("count");
int count = 0;
if (c != null) {
count = (Integer) c;
count++;
}
session.put("count", count);
return "Count @" + session.getSessionId() + " : " + count;
}
}