Browse Source

代码结构优化

zhou-hao 3 years ago
parent
commit
ed5e3b0751
15 changed files with 213 additions and 71 deletions
  1. 3 3
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationExitEvent.java
  2. 9 7
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java
  3. 1 1
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java
  4. 12 14
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java
  5. 8 3
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java
  6. 1 1
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizedToken.java
  7. 66 0
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ServletUserTokenGenPar.java
  8. 5 4
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserOnSignOut.java
  9. 32 13
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java
  10. 13 8
      hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/WebUserTokenInterceptor.java
  11. 27 0
      hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java
  12. 10 9
      hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java
  13. 3 2
      hsweb-core/src/main/java/org/hswebframework/web/context/ContextUtils.java
  14. 19 3
      hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java
  15. 4 3
      hsweb-core/src/test/java/org/hswebframework/web/logger/ReactiveLoggerTest.java

+ 3 - 3
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/events/AuthorizationExitEvent.java

@@ -19,6 +19,7 @@
 package org.hswebframework.web.authorization.events;
 
 import org.hswebframework.web.authorization.Authentication;
+import org.hswebframework.web.event.DefaultAsyncEvent;
 import org.springframework.context.ApplicationEvent;
 
 /**
@@ -26,14 +27,13 @@ import org.springframework.context.ApplicationEvent;
  *
  * @author zhouhao
  */
-public class AuthorizationExitEvent extends ApplicationEvent implements AuthorizationEvent {
+public class AuthorizationExitEvent extends DefaultAsyncEvent implements AuthorizationEvent {
 
     private static final long serialVersionUID = -4590245933665047280L;
 
-    private Authentication authentication;
+    private final Authentication authentication;
 
     public AuthorizationExitEvent(Authentication authentication) {
-        super(authentication);
         this.authentication = authentication;
     }
 

+ 9 - 7
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/ReactiveTokenAuthenticationSupplier.java

@@ -20,13 +20,15 @@ public class ReactiveTokenAuthenticationSupplier implements ReactiveAuthenticati
 
     @Override
     public Mono<Authentication> get() {
-        return ContextUtils.reactiveContext()
-                .flatMap(context ->
-                        context.get(ContextKey.of(ParsedToken.class))
-                                .map(t -> tokenManager.getByToken(t.getToken()))
-                                .orElseGet(Mono::empty))
-                .flatMap(auth -> ReactiveLogger.mdc("userId", auth.getUser().getId())
-                        .then(ReactiveLogger.mdc("username", auth.getUser().getName()))
+        return ContextUtils
+                .reactiveContext()
+                .flatMap(context -> context
+                        .get(ContextKey.of(ParsedToken.class))
+                        .map(t -> tokenManager.getByToken(t.getToken()))
+                        .orElseGet(Mono::empty))
+                .flatMap(auth -> ReactiveLogger
+                        .mdc("userId", auth.getUser().getId(),
+                             "username", auth.getUser().getName())
                         .thenReturn(auth));
     }
 }

+ 1 - 1
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenManager.java

@@ -97,7 +97,7 @@ public interface UserTokenManager {
      * @param userId userId
      * @param state  状态
      * @see org.hswebframework.web.authorization.token.event.UserTokenChangedEvent
-     * @see this#changeTokenState
+     * @see UserTokenManager#changeTokenState
      */
     Mono<Void> changeUserState(String userId, TokenState state);
 

+ 12 - 14
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserTokenReactiveAuthenticationSupplier.java

@@ -68,20 +68,18 @@ public class UserTokenReactiveAuthenticationSupplier implements ReactiveAuthenti
 
     @Override
     public Mono<Authentication> get() {
-        return ContextUtils.reactiveContext()
-                .flatMap(context ->
-                        context.get(ContextKey.of(ParsedToken.class))
-                                .map(t -> userTokenManager
-                                        .getByToken(t.getToken())
-                                        .filter(UserToken::validate))
-                                .map(tokenMono -> tokenMono
-                                        .flatMap(token -> userTokenManager
-                                                .touch(token.getToken())
-                                                .thenReturn(token))
-                                        .flatMap(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId())))
-                                .orElseGet(Mono::empty))
-                .flatMap(auth -> ReactiveLogger.mdc("userId", auth.getUser().getId())
-                        .then(ReactiveLogger.mdc("username", auth.getUser().getName()))
+        return ContextUtils
+                .reactiveContext()
+                .flatMap(context -> context
+                        .get(ContextKey.of(ParsedToken.class))
+                        .map(t -> userTokenManager.getByToken(t.getToken()).filter(UserToken::validate))
+                        .map(tokenMono -> tokenMono
+                                .flatMap(token -> userTokenManager.touch(token.getToken()).thenReturn(token))
+                                .flatMap(token -> get(thirdPartAuthenticationManager.get(token.getType()), token.getUserId())))
+                        .orElseGet(Mono::empty))
+                .flatMap(auth -> ReactiveLogger
+                        .mdc("userId", auth.getUser().getId(),
+                             "username", auth.getUser().getName())
                         .thenReturn(auth))
                 ;
 

+ 8 - 3
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/configuration/AuthorizingHandlerAutoConfiguration.java

@@ -27,6 +27,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 
+import javax.annotation.Nonnull;
 import java.util.List;
 
 /**
@@ -85,6 +86,11 @@ public class AuthorizingHandlerAutoConfiguration {
             return new UserOnSignOut(userTokenManager);
         }
 
+        @SuppressWarnings("all")
+        @ConfigurationProperties(prefix = "hsweb.authorize.token.default")
+        public ServletUserTokenGenPar servletUserTokenGenPar(){
+            return new ServletUserTokenGenPar();
+        }
 
         @Bean
         @ConditionalOnMissingBean(UserTokenParser.class)
@@ -101,11 +107,10 @@ public class AuthorizingHandlerAutoConfiguration {
         @ConditionalOnProperty(prefix = "hsweb.authorize.two-factor", name = "enable", havingValue = "true")
         @Order(100)
         public WebMvcConfigurer twoFactorHandlerConfigurer(TwoFactorValidatorManager manager) {
-            return new WebMvcConfigurerAdapter() {
+            return new WebMvcConfigurer() {
                 @Override
-                public void addInterceptors(InterceptorRegistry registry) {
+                public void addInterceptors(@Nonnull InterceptorRegistry registry) {
                     registry.addInterceptor(new TwoFactorHandlerInterceptorAdapter(manager));
-                    super.addInterceptors(registry);
                 }
             };
         }

+ 1 - 1
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/AuthorizedToken.java

@@ -3,7 +3,7 @@ package org.hswebframework.web.authorization.basic.web;
 import org.hswebframework.web.authorization.token.ParsedToken;
 
 /**
- * 已完成认证的令牌,如果返回此令牌,将直接使用{@link this#getUserId()}来绑定用户信息
+ * 已完成认证的令牌,如果返回此令牌,将直接使用{@link AuthorizedToken#getUserId()}来绑定用户信息
  *
  * @author zhouhao
  */

+ 66 - 0
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/ServletUserTokenGenPar.java

@@ -0,0 +1,66 @@
+package org.hswebframework.web.authorization.basic.web;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.web.authorization.Authentication;
+import org.hswebframework.web.authorization.token.ParsedToken;
+import org.hswebframework.web.id.IDGenerator;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+@Getter
+@Setter
+public class ServletUserTokenGenPar implements UserTokenParser, UserTokenGenerator {
+    private long timeout = TimeUnit.MINUTES.toMillis(30);
+
+    private String headerName = "X-Access-Token";
+
+    @Override
+    public String getSupportTokenType() {
+        return "default";
+    }
+
+
+    @Override
+    public GeneratedToken generate(Authentication authentication) {
+        String token = IDGenerator.MD5.generate();
+
+        return new GeneratedToken() {
+            @Override
+            public Map<String, Object> getResponse() {
+                return Collections.singletonMap("expires", timeout);
+            }
+
+            @Override
+            public String getToken() {
+                return token;
+            }
+
+            @Override
+            public String getType() {
+                return getSupportTokenType();
+            }
+
+            @Override
+            public long getTimeout() {
+                return timeout;
+            }
+        };
+    }
+
+    @Override
+    public ParsedToken parseToken(HttpServletRequest request) {
+        String token = Optional
+                .ofNullable(request.getHeader(headerName))
+                .orElseGet(() -> request.getParameter(":X_Access_Token"));
+        if (StringUtils.hasText(token)) {
+            return ParsedToken.of(getSupportTokenType(), token);
+        }
+        return null;
+    }
+}

+ 5 - 4
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserOnSignOut.java

@@ -5,12 +5,13 @@ import org.hswebframework.web.authorization.token.UserToken;
 import org.hswebframework.web.authorization.token.UserTokenHolder;
 import org.hswebframework.web.authorization.token.UserTokenManager;
 import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.EventListener;
 
 /**
  * @author zhouhao
  */
-public class UserOnSignOut implements  ApplicationListener<AuthorizationExitEvent> {
-    private UserTokenManager userTokenManager;
+public class UserOnSignOut {
+    private final UserTokenManager userTokenManager;
 
     public UserOnSignOut(UserTokenManager userTokenManager) {
         this.userTokenManager = userTokenManager;
@@ -21,8 +22,8 @@ public class UserOnSignOut implements  ApplicationListener<AuthorizationExitEven
         return null != token ? token.getToken() : "";
     }
 
-    @Override
+    @EventListener
     public void onApplicationEvent(AuthorizationExitEvent event) {
-        userTokenManager.signOutByToken(geToken());
+        event.async(userTokenManager.signOutByToken(geToken()));
     }
 }

+ 32 - 13
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/UserTokenWebFilter.java

@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 @Component
 @Slf4j
@@ -40,13 +41,28 @@ public class UserTokenWebFilter implements WebFilter, BeanPostProcessor {
     @NonNull
     public Mono<Void> filter(@NonNull ServerWebExchange exchange, WebFilterChain chain) {
 
-        return chain.filter(exchange)
-                .subscriberContext(ContextUtils.acceptContext(ctx ->
-                        Flux.fromIterable(parsers)
-                                .flatMap(parser -> parser.parseToken(exchange))
-                                .subscribe(token -> ctx.put(ParsedToken.class, token))))
-                .subscriberContext(ReactiveLogger.start("requestId", exchange.getRequest().getId()))
-                ;
+        return Flux
+                .fromIterable(parsers)
+                .flatMap(parser -> parser.parseToken(exchange))
+                .next()
+                .map(token -> chain
+                        .filter(exchange)
+                        .subscriberContext(
+                                ContextUtils.acceptContext(
+                                        context -> context.put(ParsedToken.class, token)
+                                )
+                        ))
+                .defaultIfEmpty(chain.filter(exchange))
+                .flatMap(Function.identity())
+                .subscriberContext(ReactiveLogger.start("requestId", exchange.getRequest().getId()));
+
+//        return chain.filter(exchange)
+//                .subscriberContext(ContextUtils.acceptContext(ctx ->
+//                        Flux.fromIterable(parsers)
+//                                .flatMap(parser -> parser.parseToken(exchange))
+//                                .subscribe(token -> ctx.put(ParsedToken.class, token)))
+//                )
+//                .subscriberContext(ReactiveLogger.start("requestId", exchange.getRequest().getId()))
     }
 
     @EventListener
@@ -60,14 +76,17 @@ public class UserTokenWebFilter implements WebFilter, BeanPostProcessor {
             if (StringUtils.hasText(token.getToken())) {
                 event.getResult().put("token", token.getToken());
                 long expires = event.getParameter("expires")
-                        .map(String::valueOf)
-                        .map(Long::parseLong)
-                        .orElse(token.getTimeout());
+                                    .map(String::valueOf)
+                                    .map(Long::parseLong)
+                                    .orElse(token.getTimeout());
                 event.getResult().put("expires", expires);
                 event.async(userTokenManager
-                        .signIn(token.getToken(), token.getType(), event.getAuthentication().getUser().getId(), expires)
-                        .doOnNext(t -> log.debug("user [{}] sign in", t.getUserId()))
-                        .then());
+                                    .signIn(token.getToken(), token.getType(), event
+                                            .getAuthentication()
+                                            .getUser()
+                                            .getId(), expires)
+                                    .doOnNext(t -> log.debug("user [{}] sign in", t.getUserId()))
+                                    .then());
             }
         }
 

+ 13 - 8
hsweb-authorization/hsweb-authorization-basic/src/main/java/org/hswebframework/web/authorization/basic/web/WebUserTokenInterceptor.java

@@ -22,27 +22,31 @@ import java.util.stream.Collectors;
  */
 public class WebUserTokenInterceptor extends HandlerInterceptorAdapter {
 
-    private UserTokenManager userTokenManager;
+    private final UserTokenManager userTokenManager;
 
-    private List<UserTokenParser> userTokenParser;
+    private final List<UserTokenParser> userTokenParser;
 
-    private AopMethodAuthorizeDefinitionParser parser;
+    private final AopMethodAuthorizeDefinitionParser parser;
 
-    private boolean enableBasicAuthorization = false;
+    private final boolean enableBasicAuthorization;
 
-    public WebUserTokenInterceptor(UserTokenManager userTokenManager, List<UserTokenParser> userTokenParser, AopMethodAuthorizeDefinitionParser definitionParser) {
+    public WebUserTokenInterceptor(UserTokenManager userTokenManager,
+                                   List<UserTokenParser> userTokenParser,
+                                   AopMethodAuthorizeDefinitionParser definitionParser) {
         this.userTokenManager = userTokenManager;
         this.userTokenParser = userTokenParser;
         this.parser = definitionParser;
 
-        enableBasicAuthorization = userTokenParser.stream()
+        enableBasicAuthorization = userTokenParser
+                .stream()
                 .filter(UserTokenForTypeParser.class::isInstance)
                 .anyMatch(parser -> "basic".equalsIgnoreCase(((UserTokenForTypeParser) parser).getTokenType()));
     }
 
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-        List<ParsedToken> tokens = userTokenParser.stream()
+        List<ParsedToken> tokens = userTokenParser
+                .stream()
                 .map(parser -> parser.parseToken(request))
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
@@ -68,7 +72,8 @@ public class WebUserTokenInterceptor extends HandlerInterceptorAdapter {
                 userTokenManager.signOutByToken(token).subscribe();
 
                 userToken = userTokenManager
-                        .signIn(parsedToken.getToken(), parsedToken.getType(), ((AuthorizedToken) parsedToken).getUserId(), ((AuthorizedToken) parsedToken).getMaxInactiveInterval())
+                        .signIn(parsedToken.getToken(), parsedToken.getType(), ((AuthorizedToken) parsedToken).getUserId(), ((AuthorizedToken) parsedToken)
+                                .getMaxInactiveInterval())
                         .block();
             }
             if (null != userToken) {

+ 27 - 0
hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/AccessTokenManager.java

@@ -3,14 +3,41 @@ package org.hswebframework.web.oauth2.server;
 import org.hswebframework.web.authorization.Authentication;
 import reactor.core.publisher.Mono;
 
+/**
+ * OAuth2 AccessToken管理器,用于创建,刷新token以及根据token获取权限信息
+ *
+ * @author zhouhao
+ * @since 4.0.7
+ */
 public interface AccessTokenManager {
 
+    /**
+     * 根据token获取权限信息
+     *
+     * @param accessToken accessToken
+     * @return 权限信息
+     */
     Mono<Authentication> getAuthenticationByToken(String accessToken);
 
+    /**
+     * 根据ClientId以及权限信息创建token
+     *
+     * @param clientId       clientId {@link OAuth2Client#getClientId()}
+     * @param authentication 权限信息
+     * @param singleton      是否单例,如果为true,重复创建token将返回首次创建的token
+     * @return
+     */
     Mono<AccessToken> createAccessToken(String clientId,
                                         Authentication authentication,
                                         boolean singleton);
 
+    /**
+     * 刷新token
+     *
+     * @param clientId     clientId {@link OAuth2Client#getClientId()}
+     * @param refreshToken refreshToken
+     * @return 新的token
+     */
     Mono<AccessToken> refreshAccessToken(String clientId, String refreshToken);
 
 }

+ 10 - 9
hsweb-authorization/hsweb-authorization-oauth2/src/main/java/org/hswebframework/web/oauth2/server/auth/ReactiveOAuth2AccessTokenParser.java

@@ -47,15 +47,16 @@ public class ReactiveOAuth2AccessTokenParser implements ReactiveUserTokenParser,
 
     @Override
     public Mono<Authentication> get() {
-        return ContextUtils.reactiveContext()
-                .flatMap(context ->
-                        context.get(ContextKey.of(ParsedToken.class))
-                                .filter(token -> "oauth2".equals(token.getType()))
-                                .map(t -> accessTokenManager
-                                        .getAuthenticationByToken(t.getToken()))
-                                .orElse(Mono.empty()))
-                .flatMap(auth -> ReactiveLogger.mdc("userId", auth.getUser().getId())
-                        .then(ReactiveLogger.mdc("username", auth.getUser().getName()))
+        return ContextUtils
+                .reactiveContext()
+                .flatMap(context -> context
+                        .get(ContextKey.of(ParsedToken.class))
+                        .filter(token -> "oauth2".equals(token.getType()))
+                        .map(t -> accessTokenManager.getAuthenticationByToken(t.getToken()))
+                        .orElse(Mono.empty()))
+                .flatMap(auth -> ReactiveLogger
+                        .mdc("userId", auth.getUser().getId(),
+                             "username", auth.getUser().getName())
                         .thenReturn(auth));
     }
 }

+ 3 - 2
hsweb-core/src/main/java/org/hswebframework/web/context/ContextUtils.java

@@ -18,11 +18,12 @@ public class ContextUtils {
     }
 
     public static Mono<Context> reactiveContext() {
-        return Mono.subscriberContext()
+        return Mono
+                .subscriberContext()
                 .<Context>handle((context, sink) -> {
                     if (context.hasKey(Context.class)) {
                         sink.next(context.get(Context.class));
-                    }else {
+                    } else {
                         sink.complete();
                     }
                 })

+ 19 - 3
hsweb-core/src/main/java/org/hswebframework/web/logger/ReactiveLogger.java

@@ -13,17 +13,32 @@ import java.util.function.Function;
 @Slf4j
 public class ReactiveLogger {
 
-    private static String CONTEXT_KEY = ReactiveLogger.class.getName();
+    private static final String CONTEXT_KEY = ReactiveLogger.class.getName();
 
     public static Function<Context, Context> start(String key, String value) {
         return start(Collections.singletonMap(key, value));
     }
 
+    public static Function<Context, Context> start(String... keyAndValue) {
+        Map<String, String> map = new HashMap<>();
+        for (int i = 0, len = keyAndValue.length / 2; i < len; i++) {
+            map.put(keyAndValue[i * 2], keyAndValue[i * 2 + 1]);
+        }
+        return start(map);
+    }
+
     public static Mono<Void> mdc(String key, String value) {
-        return Mono.<Void>empty()
+        return Mono
+                .<Void>empty()
                 .subscriberContext(start(key, value));
     }
 
+    public static Mono<Void> mdc(String... keyAndValue) {
+        return Mono
+                .<Void>empty()
+                .subscriberContext(start(keyAndValue));
+    }
+
     public static Function<Context, Context> start(Map<String, String> context) {
         return ctx -> {
             Optional<Map<String, String>> maybeContextMap = ctx.getOrEmpty(CONTEXT_KEY);
@@ -74,7 +89,8 @@ public class ReactiveLogger {
     }
 
     public static Mono<Void> mdc(Consumer<Map<String, String>> consumer) {
-        return Mono.subscriberContext()
+        return Mono
+                .subscriberContext()
                 .doOnNext(ctx -> {
                     Optional<Map<String, String>> maybeContextMap = ctx.getOrEmpty(CONTEXT_KEY);
                     if (maybeContextMap.isPresent()) {

+ 4 - 3
hsweb-core/src/test/java/org/hswebframework/web/logger/ReactiveLoggerTest.java

@@ -2,6 +2,7 @@ package org.hswebframework.web.logger;
 
 import lombok.extern.slf4j.Slf4j;
 import org.junit.Test;
+import org.slf4j.MDC;
 import reactor.core.publisher.Flux;
 import reactor.test.StepVerifier;
 
@@ -17,12 +18,12 @@ public class ReactiveLoggerTest {
     public void test() {
 
         Flux.range(0, 5)
-                .delayElements(Duration.ofSeconds(1))
                 .flatMap(i -> ReactiveLogger.mdc("requestId", "test").thenReturn(i))
                 .doOnEach(ReactiveLogger.onNext(v -> {
-                    log.info("test:{}", v);
+
+                    log.info("test:{} {}", v, MDC.getCopyOfContextMap());
                 }))
-                .subscriberContext(ReactiveLogger.start("r", "1"))
+                .subscriberContext(ReactiveLogger.start("r", "1","t","1"))
                 .as(StepVerifier::create)
                 .expectNextCount(5)
                 .verifyComplete();