zhouhao vor 7 Jahren
Ursprung
Commit
f1ad06cbcd
11 geänderte Dateien mit 215 neuen und 79 gelöschten Zeilen
  1. 0 24
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/UserToken.java
  2. 19 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/AllopatricLoginMode.java
  3. 58 26
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/MemeoryAuthenticationContainer.java
  4. 13 2
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/SimpleUserToken.java
  5. 26 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/TokenState.java
  6. 63 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserToken.java
  7. 22 12
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/AuthenticationContainer.java
  8. 2 2
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/event/UserSignInEvent.java
  9. 6 6
      hsweb-message/hsweb-message-websocket/src/main/java/org/hswebframework/web/socket/handler/CommandWebSocketMessageDispatcher.java
  10. 3 4
      hsweb-message/hsweb-message-websocket/src/main/java/org/hswebframework/web/socket/handler/WebSocketUtils.java
  11. 3 3
      hsweb-message/hsweb-message-websocket/src/main/java/org/hswebframework/web/socket/starter/CommandWebSocketAutoConfiguration.java

+ 0 - 24
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/UserToken.java

@@ -1,24 +0,0 @@
-package org.hswebframework.web.authorization.container;
-
-
-import java.io.Serializable;
-
-/**
- * Created by zhouhao on 2017/7/7.
- */
-public interface UserToken extends Serializable, Comparable<UserToken> {
-    String getUserId();
-
-    String getToken();
-
-    long getRequestTimes();
-
-    long getLastRequestTime();
-
-    long getSignInTime();
-
-    @Override
-    default int compareTo(UserToken o) {
-        return Long.valueOf(getSignInTime()).compareTo(o.getSignInTime());
-    }
-}

+ 19 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/AllopatricLoginMode.java

@@ -0,0 +1,19 @@
+package org.hswebframework.web.authorization.token;
+
+/**
+ * 异地登录模式
+ */
+public enum AllopatricLoginMode {
+    /**
+     * 如果用户已在其他地方登录,则拒绝登录
+     */
+    deny,
+    /**
+     * 可以登录,同一个用户可在不同的地点登录
+     */
+    allow,
+    /**
+     * 如果用户已在其他地方登录,则将已登录的用户踢下线
+     */
+    offlineOther
+}

+ 58 - 26
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/MemeoryAuthenticationContainer.java

@@ -16,15 +16,12 @@
  *
  */
 
-package org.hswebframework.web.authorization.container;
+package org.hswebframework.web.authorization.token;
 
-import org.hswebframework.web.authorization.AuthenticationManager;
-import org.hswebframework.web.authorization.container.event.UserSignInEvent;
+import org.hswebframework.web.authorization.token.event.UserSignInEvent;
 import org.hswebframework.web.authorization.listener.AuthorizationListenerDispatcher;
 
 import java.util.List;
-import java.util.Map;
-import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.stream.Collectors;
@@ -35,20 +32,18 @@ import java.util.stream.Collectors;
  * @author zhouhao
  * @since 3.0
  */
-public class MemeoryAuthenticationContainer implements AuthenticationContainer {
+public class MemeoryUserTokenManager implements UserTokenManager {
 
-    private ConcurrentMap<String, SimpleUserToken> tokenUserStorage = new ConcurrentHashMap<>(256);
+    private final ConcurrentMap<String, SimpleUserToken> tokenUserStorage = new ConcurrentHashMap<>(256);
 
-    private AuthenticationManager authenticationManager;
-
-    // timeout seconds
+    //令牌超时事件,默认3600秒
     private long timeout = 3600;
 
-    private AuthorizationListenerDispatcher authorizationListenerDispatcher;
+    //异地登录模式,默认运行异地登录
+    private AllopatricLoginMode allopatricLoginMode=AllopatricLoginMode.allow;
 
-    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
-        this.authenticationManager = authenticationManager;
-    }
+    //事件转发器
+    private AuthorizationListenerDispatcher authorizationListenerDispatcher;
 
     public void setAuthorizationListenerDispatcher(AuthorizationListenerDispatcher authorizationListenerDispatcher) {
         this.authorizationListenerDispatcher = authorizationListenerDispatcher;
@@ -62,17 +57,26 @@ public class MemeoryAuthenticationContainer implements AuthenticationContainer {
         return timeout;
     }
 
-    private UserToken checkTimeout(UserToken detail) {
+    public void setAllopatricLoginMode(AllopatricLoginMode allopatricLoginMode) {
+        this.allopatricLoginMode = allopatricLoginMode;
+    }
+
+    public AllopatricLoginMode getAllopatricLoginMode() {
+        return allopatricLoginMode;
+    }
+
+    private SimpleUserToken checkTimeout(SimpleUserToken detail) {
         if (null == detail) return null;
         if (System.currentTimeMillis() - detail.getLastRequestTime() > timeout * 1000) {
-            logoutByToken(detail.getToken());
-            return null;
+            detail.setState(TokenState.expired);
+           // logoutByToken(detail.getToken());
+            return detail;
         }
         return detail;
     }
 
     @Override
-    public UserToken getByToken(String token) {
+    public SimpleUserToken getByToken(String token) {
         return checkTimeout(tokenUserStorage.get(token));
     }
 
@@ -85,29 +89,45 @@ public class MemeoryAuthenticationContainer implements AuthenticationContainer {
 
     @Override
     public boolean userIsLoggedIn(String userId) {
-        return getByUserId(userId).size() > 0;
+        for (UserToken userToken : getByUserId(userId)) {
+            if(userToken.isEffective())return true;
+        }
+        return false;
     }
 
     @Override
     public boolean tokenIsLoggedIn(String token) {
-        return getByToken(token) != null;
+        UserToken userToken=getByToken(token);
+
+        return userToken != null&&userToken.isEffective();
     }
 
     @Override
-    public int totalUser() {
-        return tokenUserStorage.values().stream().map(UserToken::getUserId).distinct().mapToInt(userId->1).sum();
+    public long totalUser() {
+        return tokenUserStorage.values()
+                .stream()
+                .peek(this::checkTimeout)//检查是否已经超时
+                .filter(UserToken::isEffective)//只返回有效的
+                .map(UserToken::getUserId)
+                .distinct()//去重复
+                .count();
     }
 
     @Override
-    public int totalToken() {
-        return tokenUserStorage.size();
+    public long totalToken() {
+        return tokenUserStorage.values()
+                .stream()
+                .peek(this::checkTimeout)//检查是否已经超时
+                .filter(UserToken::isEffective)//只返回有效的
+                .count();
     }
 
     @Override
     public List<UserToken> allLoggedUser() {
-        return tokenUserStorage.values().stream()
+        return tokenUserStorage.values()
+                .stream()
                 .map(this::checkTimeout)
-                .filter(Objects::nonNull)
+                .filter(UserToken::isEffective)
                 .collect(Collectors.toList());
     }
 
@@ -126,6 +146,18 @@ public class MemeoryAuthenticationContainer implements AuthenticationContainer {
         SimpleUserToken detail = new SimpleUserToken(userId, token);
         if (null != authorizationListenerDispatcher)
             authorizationListenerDispatcher.doEvent(new UserSignInEvent(detail));
+        if(allopatricLoginMode==AllopatricLoginMode.deny){
+            detail.setState(TokenState.deny);
+        }else if (allopatricLoginMode==AllopatricLoginMode.offlineOther){
+            detail.setState(TokenState.effective);
+            SimpleUserToken oldToken =(SimpleUserToken) getByUserId(userId);
+            if(oldToken!=null){
+                //踢下线
+                oldToken.setState(TokenState.offline);
+            }
+        }else{
+            detail.setState(TokenState.effective);
+        }
         tokenUserStorage.put(token, detail);
         return detail;
     }

+ 13 - 2
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/SimpleUserToken.java

@@ -1,4 +1,4 @@
-package org.hswebframework.web.authorization.container;
+package org.hswebframework.web.authorization.token;
 
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -11,6 +11,8 @@ public class SimpleUserToken implements UserToken {
 
     private String token;
 
+    private TokenState state;
+
     private AtomicLong requestTimesCounter=new AtomicLong(0);
 
     private volatile long lastRequestTime=System.currentTimeMillis();
@@ -52,6 +54,15 @@ public class SimpleUserToken implements UserToken {
         return token;
     }
 
+    @Override
+    public TokenState getState() {
+        return state;
+    }
+
+    public void setState(TokenState state) {
+        this.state = state;
+    }
+
     public void setUserId(String userId) {
         this.userId = userId;
     }
@@ -73,7 +84,7 @@ public class SimpleUserToken implements UserToken {
         requestTimesCounter.set(requestTimes);
     }
 
-    public  synchronized void touch(){
+    public  void touch(){
         requestTimesCounter.addAndGet(1);
         lastRequestTime=System.currentTimeMillis();
     }

+ 26 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/TokenState.java

@@ -0,0 +1,26 @@
+package org.hswebframework.web.authorization.token;
+
+/**
+ * 令牌状态
+ */
+public enum TokenState {
+    /**
+     * 正常,有效
+     */
+    effective,
+
+    /**
+     * 已被禁止访问
+     */
+    deny,
+
+    /**
+     * 已过期
+     */
+    expired,
+
+    /**
+     * 已被踢下线
+     */
+    offline
+}

+ 63 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/UserToken.java

@@ -0,0 +1,63 @@
+package org.hswebframework.web.authorization.token;
+
+
+import org.hswebframework.web.authorization.User;
+
+import java.io.Serializable;
+
+/**
+ * 用户的token信息
+ * @author zhouhao
+ * @since 3.0
+ */
+public interface UserToken extends Serializable, Comparable<UserToken> {
+    /**
+     *
+     * @return 用户id
+     * @see  User#getId()
+     */
+    String getUserId();
+
+    /**
+     *
+     * @return token
+     */
+    String getToken();
+
+    /**
+     *
+     * @return 请求总次数
+     */
+    long getRequestTimes();
+
+    /**
+     *
+     * @return 最后一次请求时间
+     */
+    long getLastRequestTime();
+
+    /**
+     *
+     * @return 首次请求时间
+     */
+    long getSignInTime();
+
+    TokenState getState();
+
+    default boolean isEffective(){
+        return getState()==TokenState.effective;
+    }
+
+    default boolean isExpired(){
+        return getState()==TokenState.expired;
+    }
+
+    default boolean isOffline(){
+        return getState()==TokenState.offline;
+    }
+
+    @Override
+    default int compareTo(UserToken target) {
+        return Long.valueOf(getSignInTime()).compareTo(target.getSignInTime());
+    }
+}

+ 22 - 12
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/AuthenticationContainer.java

@@ -16,28 +16,28 @@
  *
  */
 
-package org.hswebframework.web.authorization.container;
+package org.hswebframework.web.authorization.token;
 
 import java.util.List;
 
 /**
- * 授权容器,用来操作所有已经授权的用户
+ * 用户授权容器,用来操作所有已经授权的用户
  *
  * @author zhouhao
  * @since 3.0
  */
-public interface AuthenticationContainer {
+public interface UserTokenManager {
 
     /**
-     * 根据token获取权限信息
+     * 根据token获取用户令牌信息
      *
-     * @param token
-     * @return 权限信息, 未授权时返回null
+     * @param token token
+     * @return 令牌信息, 未授权时返回null
      */
     UserToken getByToken(String token);
 
     /**
-     * 根据用户id,获取全部授权信息,如果设置了不能跨地点登陆,返回值只可能是{@code null}或者size为1的list
+     * 根据用户id,获取全部令牌信息,如果设置了不能跨地点登陆,返回值只可能是{@code null}或者size为1的list
      * @param userId 用户id
      * @return 授权信息
      */
@@ -49,18 +49,24 @@ public interface AuthenticationContainer {
      */
     boolean userIsLoggedIn(String userId);
 
+    /**
+     *
+     * @param token token
+     * @return token是否已登记
+     */
     boolean tokenIsLoggedIn(String token);
 
     /**
      * @return 总用户数量,一个用户多个地方登陆数量算1
      */
-    int totalUser();
+    long totalUser();
 
     /**
      *
      * @return 总token数量
      */
-    int totalToken();
+    long totalToken();
+
     /**
      * @return 所有被授权的用户
      */
@@ -80,11 +86,15 @@ public interface AuthenticationContainer {
     void logoutByToken(String token);
 
     /**
-     * @param token
-     * @param userId
+     * 登记一个用户的token
+     * @param token token
+     * @param userId 用户id
      */
     UserToken signIn(String token, String userId);
 
-
+    /**
+     * 更新token,使其不过期
+     * @param token token
+     */
     void touch(String token);
 }

+ 2 - 2
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/container/event/UserSignInEvent.java

@@ -1,6 +1,6 @@
-package org.hswebframework.web.authorization.container.event;
+package org.hswebframework.web.authorization.token.event;
 
-import org.hswebframework.web.authorization.container.UserToken;
+import org.hswebframework.web.authorization.token.UserToken;
 import org.hswebframework.web.authorization.listener.event.AuthorizationEvent;
 
 /**

+ 6 - 6
hsweb-message/hsweb-message-websocket/src/main/java/org/hswebframework/web/socket/handler/CommandWebSocketMessageDispatcher.java

@@ -3,7 +3,7 @@ package org.hswebframework.web.socket.handler;
 import com.alibaba.fastjson.JSON;
 import com.fasterxml.jackson.core.JsonParseException;
 import org.hswebframework.web.authorization.Authentication;
-import org.hswebframework.web.authorization.container.AuthenticationContainer;
+import org.hswebframework.web.authorization.token.UserTokenManager;
 import org.hswebframework.web.socket.CommandRequest;
 import org.hswebframework.web.socket.WebSocketSessionListener;
 import org.hswebframework.web.socket.message.WebSocketMessage;
@@ -25,7 +25,7 @@ public class CommandWebSocketMessageDispatcher extends TextWebSocketHandler {
 
     private CommandProcessorContainer processorContainer;
 
-    private AuthenticationContainer authenticationContainer;
+    private UserTokenManager userTokenManager;
 
     private List<WebSocketSessionListener> webSocketSessionListeners;
 
@@ -33,8 +33,8 @@ public class CommandWebSocketMessageDispatcher extends TextWebSocketHandler {
         this.webSocketSessionListeners = webSocketSessionListeners;
     }
 
-    public void setAuthenticationContainer(AuthenticationContainer authenticationContainer) {
-        this.authenticationContainer = authenticationContainer;
+    public void setUserTokenManager(UserTokenManager userTokenManager) {
+        this.userTokenManager = userTokenManager;
     }
 
     public void setProcessorContainer(CommandProcessorContainer processorContainer) {
@@ -67,8 +67,8 @@ public class CommandWebSocketMessageDispatcher extends TextWebSocketHandler {
     }
 
     private Authentication getAuthenticationFromSession(WebSocketSession socketSession) {
-        if (null == authenticationContainer) return null;
-        return WebSocketUtils.getAuthentication(authenticationContainer, socketSession);
+        if (null == userTokenManager) return null;
+        return WebSocketUtils.getAuthentication(userTokenManager, socketSession);
     }
 
     private CommandRequest buildCommand(WebSocketCommandRequest request, WebSocketSession socketSession) {

+ 3 - 4
hsweb-message/hsweb-message-websocket/src/main/java/org/hswebframework/web/socket/handler/WebSocketUtils.java

@@ -1,12 +1,11 @@
 package org.hswebframework.web.socket.handler;
 
 import org.hswebframework.web.authorization.Authentication;
-import org.hswebframework.web.authorization.container.AuthenticationContainer;
+import org.hswebframework.web.authorization.token.UserTokenManager;
 import org.springframework.http.HttpHeaders;
 import org.springframework.web.socket.WebSocketSession;
 
 import java.util.*;
-import java.util.function.Function;
 
 /**
  * TODO 完成注释
@@ -16,7 +15,7 @@ import java.util.function.Function;
 public class WebSocketUtils {
 
 
-    public static Authentication getAuthentication(AuthenticationContainer container, WebSocketSession session) {
+    public static Authentication getAuthentication(UserTokenManager container, WebSocketSession session) {
         Authentication authentication = Authentication
                 .current()
                 .orElseGet(() -> ((Authentication) session.getAttributes().get(Authentication.class.getName())));
@@ -40,7 +39,7 @@ public class WebSocketUtils {
         throw new UnsupportedOperationException();
 //        Function<Set<String>, Optional<Authentication>> userGetter = set ->
 //                set == null ? Optional.empty() : set.stream()
-//                        .map(container::getByToken)
+//                        .map(token::getByToken)
 //                        .filter(Objects::nonNull)
 //                        .findFirst();
 //

+ 3 - 3
hsweb-message/hsweb-message-websocket/src/main/java/org/hswebframework/web/socket/starter/CommandWebSocketAutoConfiguration.java

@@ -1,6 +1,6 @@
 package org.hswebframework.web.socket.starter;
 
-import org.hswebframework.web.authorization.container.AuthenticationContainer;
+import org.hswebframework.web.authorization.token.UserTokenManager;
 import org.hswebframework.web.concurrent.counter.CounterManager;
 import org.hswebframework.web.message.Messager;
 import org.hswebframework.web.socket.WebSocketSessionListener;
@@ -60,7 +60,7 @@ public class CommandWebSocketAutoConfiguration {
     @Configuration
     public static class HandlerConfigruation extends WebSocketConfigurationSupport {
         @Autowired(required = false)
-        private AuthenticationContainer authenticationContainer;
+        private UserTokenManager userTokenManager;
 
         @Autowired(required = false)
         private List<WebSocketSessionListener> webSocketSessionListeners;
@@ -72,7 +72,7 @@ public class CommandWebSocketAutoConfiguration {
         protected void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
             CommandWebSocketMessageDispatcher dispatcher = new CommandWebSocketMessageDispatcher();
             dispatcher.setProcessorContainer(commandProcessorContainer);
-            dispatcher.setAuthenticationContainer(authenticationContainer);
+            dispatcher.setUserTokenManager(userTokenManager);
             dispatcher.setWebSocketSessionListeners(webSocketSessionListeners);
             registry.addHandler(dispatcher, "/sockjs")
                     .withSockJS()