소스 검색

rememberme

MaxKey 3 년 전
부모
커밋
5f0f1fa7e0
16개의 변경된 파일550개의 추가작업 그리고 72개의 파일을 삭제
  1. 8 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/jwt/AuthJwt.java
  2. 0 2
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/jwt/AuthJwtService.java
  3. 3 3
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/session/Session.java
  4. 124 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/AbstractRemeberMeService.java
  5. 54 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/InMemoryRemeberMeService.java
  6. 109 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/JdbcRemeberMeService.java
  7. 97 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/RemeberMe.java
  8. 47 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/RemeberMeServiceFactory.java
  9. 19 2
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java
  10. 3 21
      maxkey-core/src/main/java/org/maxkey/web/WebConstants.java
  11. 0 6
      maxkey-core/src/main/java/org/maxkey/web/WebContext.java
  12. 33 23
      maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/login/login.component.ts
  13. 4 1
      maxkey-web-frontend/maxkey-web-app/src/app/service/authentication.service.ts
  14. 1 1
      maxkey-web-frontend/maxkey-web-app/src/app/shared/consts.ts
  15. 45 12
      maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/LoginEntryPoint.java
  16. 3 1
      maxkey-webs/maxkey-web-maxkey/src/main/resources/application-http.properties

+ 8 - 0
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/jwt/AuthJwt.java

@@ -32,6 +32,7 @@ public class AuthJwt implements Serializable {
 	private String ticket;
 	private String token;
 	private String type = "Bearer";
+	private String remeberMe;
 	private String id;
 	private String name;
 	private String username;
@@ -157,6 +158,13 @@ public class AuthJwt implements Serializable {
 		this.passwordSetType = passwordSetType;
 	}
 	
+	public String getRemeberMe() {
+		return remeberMe;
+	}
+
+	public void setRemeberMe(String remeberMe) {
+		this.remeberMe = remeberMe;
+	}
 
 	@Override
 	public String toString() {

+ 0 - 2
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/jwt/AuthJwtService.java

@@ -64,8 +64,6 @@ public class AuthJwtService {
 		this.momentaryService = momentaryService;
 		
 		this.hmac512Service = new HMAC512Service(authJwkConfig.getSecret());
-		
-		
 	}
 	
 	/**

+ 3 - 3
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/session/Session.java

@@ -69,11 +69,11 @@ public class Session implements Serializable{
 	}
 
 	public String getFormattedId() {
-        return id;
+        return SESSION_PREFIX + id;
     }
 
-    public void setId(String ticketId) {
-        this.id = ticketId;
+    public void setId(String sessionId) {
+        this.id = sessionId;
     }
     
 

+ 124 - 0
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/AbstractRemeberMeService.java

@@ -0,0 +1,124 @@
+/*
+ * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+package org.maxkey.authn.support.rememberme;
+
+import java.text.ParseException;
+import java.util.Date;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.joda.time.DateTime;
+import org.maxkey.authn.SignPrincipal;
+import org.maxkey.authn.jwt.AuthJwtService;
+import org.maxkey.configuration.ApplicationConfig;
+import org.maxkey.crypto.jwt.HMAC512Service;
+import org.maxkey.entity.UserInfo;
+import org.maxkey.util.DateUtils;
+import org.maxkey.web.WebContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+
+public abstract class AbstractRemeberMeService {
+    private static final Logger _logger = LoggerFactory.getLogger(AbstractRemeberMeService.class);
+
+    protected Integer validity = 7;
+
+    protected ApplicationConfig applicationConfig;
+    
+    AuthJwtService authJwtService;
+
+    // follow function is for persist
+    public abstract void save(RemeberMe remeberMe);
+
+    public abstract void update(RemeberMe remeberMe);
+
+    public abstract RemeberMe read(RemeberMe remeberMe);
+
+    public abstract void remove(String username);
+    // end persist
+
+    public String createRemeberMe(Authentication  authentication, 
+    					HttpServletRequest request, HttpServletResponse response) {
+        if (applicationConfig.getLoginConfig().isRemeberMe()) {
+        	SignPrincipal principal = ((SignPrincipal)authentication.getPrincipal());
+    		UserInfo userInfo = principal.getUserInfo();
+            _logger.debug("Remeber Me ...");
+            RemeberMe remeberMe = new RemeberMe();
+            remeberMe.setId(WebContext.genId());
+            remeberMe.setUserId(userInfo.getId());
+            remeberMe.setUsername(userInfo.getUsername());
+            remeberMe.setLastLoginTime(DateUtils.getCurrentDate());
+            remeberMe.setExpirationTime(DateTime.now().plusDays(validity).toDate());
+            save(remeberMe);
+            _logger.debug("Remeber Me " + remeberMe);
+            return genRemeberMe(remeberMe);
+        }
+        return null;
+    }
+
+    public String updateRemeberMe(RemeberMe remeberMe) {
+        remeberMe.setLastLoginTime(new Date());
+        remeberMe.setExpirationTime(DateTime.now().plusDays(validity).toDate());
+        update(remeberMe);
+        _logger.debug("update Remeber Me " + remeberMe);
+        
+        return genRemeberMe(remeberMe);
+    }
+
+    public boolean removeRemeberMe(HttpServletResponse response,UserInfo currentUser) {
+        remove(currentUser.getUsername());
+
+        return true;
+    }
+    
+    public RemeberMe resolve(String rememberMeToken) throws ParseException {
+    	JWTClaimsSet claims = authJwtService.resolve(rememberMeToken);
+    	RemeberMe remeberMe = new RemeberMe();
+		remeberMe.setId(claims.getJWTID());
+		remeberMe.setUsername(claims.getSubject());
+		return read(remeberMe);
+    }
+    
+    public String genRemeberMe(RemeberMe remeberMe ) {
+		_logger.debug("expiration Time : {}" , remeberMe.getExpirationTime());
+		
+		 JWTClaimsSet remeberMeJwtClaims =new  JWTClaimsSet.Builder()
+				.issuer("")
+				.subject(remeberMe.getUsername())
+				.jwtID(remeberMe.getId())
+				.issueTime(remeberMe.getLastLoginTime())
+				.expirationTime(remeberMe.getExpirationTime())
+				.claim("kid", HMAC512Service.MXK_AUTH_JWK)
+				.build();
+		
+		return authJwtService.signedJWT(remeberMeJwtClaims);
+	}
+
+	public Integer getValidity() {
+		return validity;
+	}
+
+	public void setValidity(Integer validity) {
+		this.validity = validity;
+	}
+    
+
+}

+ 54 - 0
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/InMemoryRemeberMeService.java

@@ -0,0 +1,54 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+package org.maxkey.authn.support.rememberme;
+
+import java.util.concurrent.TimeUnit;
+
+import org.maxkey.constants.ConstsTimeInterval;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+
+public class InMemoryRemeberMeService   extends AbstractRemeberMeService {
+
+    protected static final Cache<String, RemeberMe> remeberMeStore = 
+            Caffeine.newBuilder()
+                .expireAfterWrite(ConstsTimeInterval.TWO_WEEK, TimeUnit.SECONDS)
+                .build();
+    
+    @Override
+    public void save(RemeberMe remeberMe) {
+        remeberMeStore.put(remeberMe.getUsername(), remeberMe);
+    }
+
+    @Override
+    public void update(RemeberMe remeberMe) {
+        remeberMeStore.put(remeberMe.getUsername(), remeberMe);
+    }
+
+    @Override
+    public RemeberMe read(RemeberMe remeberMe) {
+        return remeberMeStore.getIfPresent(remeberMe.getUsername());
+    }
+
+    @Override
+    public void remove(String username) {
+        remeberMeStore.invalidate(username);
+    }
+
+}

+ 109 - 0
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/JdbcRemeberMeService.java

@@ -0,0 +1,109 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+package org.maxkey.authn.support.rememberme;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.List;
+
+import org.maxkey.authn.jwt.AuthJwtService;
+import org.maxkey.configuration.ApplicationConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+
+public class JdbcRemeberMeService extends AbstractRemeberMeService {
+    private static final Logger _logger = LoggerFactory.getLogger(JdbcRemeberMeService.class);
+
+    private static final String DEFAULT_DEFAULT_INSERT_STATEMENT = 
+            "insert into  mxk_remember_me(id, userid,username,lastlogintime,expirationtime)values( ? , ? , ? , ? , ?)";
+
+    private static final String DEFAULT_DEFAULT_SELECT_STATEMENT = 
+            "select id, userid,username,lastlogintime,expirationtime  from mxk_remember_me " 
+                    + " where id = ?  and username = ?";
+
+    private static final String DEFAULT_DEFAULT_DELETE_STATEMENT = 
+            "delete from  mxk_remember_me where  username = ?";
+
+    private static final String DEFAULT_DEFAULT_UPDATE_STATEMENT = 
+            "update mxk_remember_me  set  lastlogintime = ? , expirationtime = ?  where id = ?";
+
+    private final JdbcTemplate jdbcTemplate;
+
+    public JdbcRemeberMeService(
+    			JdbcTemplate jdbcTemplate,
+    			ApplicationConfig applicationConfig,
+    			AuthJwtService authJwtService) {
+        this.jdbcTemplate = jdbcTemplate;
+        this.applicationConfig = applicationConfig;
+        this.authJwtService = authJwtService;
+    }
+
+    @Override
+    public void save(RemeberMe remeberMe) {
+        jdbcTemplate.update(DEFAULT_DEFAULT_INSERT_STATEMENT,
+                new Object[] { 
+                			remeberMe.getId(), 
+                			remeberMe.getUserId(),
+                			remeberMe.getUsername(), 
+                			remeberMe.getLastLoginTime(),
+                			remeberMe.getExpirationTime()},
+                new int[] { 
+                			Types.VARCHAR, 
+                			Types.VARCHAR, 
+                			Types.VARCHAR, 
+                			Types.TIMESTAMP,
+                			Types.TIMESTAMP 
+                		});
+    }
+
+    @Override
+    public void update(RemeberMe remeberMe) {
+        jdbcTemplate.update(DEFAULT_DEFAULT_UPDATE_STATEMENT,
+                new Object[] { 
+                        remeberMe.getLastLoginTime(), 
+                        remeberMe.getExpirationTime(),
+                        remeberMe.getId() 
+                });
+    }
+
+    @Override
+    public RemeberMe read(RemeberMe remeberMe) {
+        List<RemeberMe> listRemeberMe = jdbcTemplate.query(DEFAULT_DEFAULT_SELECT_STATEMENT,
+                new RowMapper<RemeberMe>() {
+                    public RemeberMe mapRow(ResultSet rs, int rowNum) throws SQLException {
+                        RemeberMe remeberMe = new RemeberMe();
+                        remeberMe.setId(rs.getString(1));
+                        remeberMe.setUserId(rs.getString(2));
+                        remeberMe.setUsername(rs.getString(3));
+                        remeberMe.setLastLoginTime(rs.getDate(4));
+                        return remeberMe;
+                    }
+                }, remeberMe.getId(), remeberMe.getUsername());
+        _logger.debug("listRemeberMe " + listRemeberMe);
+        return (listRemeberMe.size() > 0) ? listRemeberMe.get(0) : null;
+    }
+
+    @Override
+    public void remove(String username) {
+        jdbcTemplate.update(DEFAULT_DEFAULT_DELETE_STATEMENT, username);
+    }
+
+}

+ 97 - 0
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/RemeberMe.java

@@ -0,0 +1,97 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+package org.maxkey.authn.support.rememberme;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class RemeberMe implements Serializable {
+
+    private static final long serialVersionUID = 8010496585233991785L;
+
+    String id;
+
+    String userId;
+    
+    String username;
+
+    Date lastLoginTime;
+    
+    Date expirationTime;
+
+    public RemeberMe() {
+		super();
+	}
+
+	public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+
+	public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Date getLastLoginTime() {
+		return lastLoginTime;
+	}
+
+	public void setLastLoginTime(Date lastLoginTime) {
+		this.lastLoginTime = lastLoginTime;
+	}
+
+	public Date getExpirationTime() {
+		return expirationTime;
+	}
+
+	public void setExpirationTime(Date expirationTime) {
+		this.expirationTime = expirationTime;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		builder.append("RemeberMe [id=");
+		builder.append(id);
+		builder.append(", userId=");
+		builder.append(userId);
+		builder.append(", username=");
+		builder.append(username);
+		builder.append(", lastLoginTime=");
+		builder.append(lastLoginTime);
+		builder.append(", expirationTime=");
+		builder.append(expirationTime);
+		builder.append("]");
+		return builder.toString();
+	}
+}

+ 47 - 0
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/rememberme/RemeberMeServiceFactory.java

@@ -0,0 +1,47 @@
+/*
+ * Copyright [2021] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+package org.maxkey.authn.support.rememberme;
+
+import org.maxkey.constants.ConstsPersistence;
+import org.maxkey.persistence.redis.RedisConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+public class RemeberMeServiceFactory {
+	private static final  Logger _logger = 
+            LoggerFactory.getLogger(RemeberMeServiceFactory.class);
+	
+	 public AbstractRemeberMeService getService(
+			 	int persistence,
+			 	JdbcTemplate jdbcTemplate,
+	            RedisConnectionFactory redisConnFactory){
+		 
+		 AbstractRemeberMeService remeberMeService = null;
+	        if (persistence == ConstsPersistence.INMEMORY) {
+	            remeberMeService = new InMemoryRemeberMeService();
+	            _logger.debug("InMemoryRemeberMeService");
+	        } else if (persistence == ConstsPersistence.JDBC) {
+	            //remeberMeService = new JdbcRemeberMeService(jdbcTemplate);
+	            _logger.debug("JdbcRemeberMeService not support "); 
+	        } else if (persistence == ConstsPersistence.REDIS) {
+	            _logger.debug("RedisRemeberMeService  not support ");
+	        }
+	        return remeberMeService;
+	}
+}

+ 19 - 2
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java

@@ -30,6 +30,8 @@ import org.maxkey.authn.provider.TrustedAuthenticationProvider;
 import org.maxkey.authn.realm.AbstractAuthenticationRealm;
 import org.maxkey.authn.session.SessionManager;
 import org.maxkey.authn.session.SessionManagerFactory;
+import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
+import org.maxkey.authn.support.rememberme.JdbcRemeberMeService;
 import org.maxkey.authn.web.HttpSessionListenerAdapter;
 import org.maxkey.configuration.ApplicationConfig;
 import org.maxkey.configuration.AuthJwkConfig;
@@ -181,7 +183,7 @@ public class AuthenticationAutoConfiguration  implements InitializingBean {
     }
     
     
-    @Bean(name = "sessionManager")
+    @Bean
     public SessionManager sessionManager(
             @Value("${maxkey.server.persistence}") int persistence,
             JdbcTemplate jdbcTemplate,
@@ -195,7 +197,22 @@ public class AuthenticationAutoConfiguration  implements InitializingBean {
         return sessionManager;
     }
     
-    @Bean(name = "httpSessionListenerAdapter")
+    
+    /**
+     * remeberMeService .
+     * @return
+     */
+    @Bean
+    public AbstractRemeberMeService remeberMeService(
+            @Value("${maxkey.server.persistence}") int persistence,
+            @Value("${maxkey.login.remeberme.validity}") int validity,
+            ApplicationConfig applicationConfig,
+            AuthJwtService authJwtService,
+            JdbcTemplate jdbcTemplate) {
+        return new  JdbcRemeberMeService(jdbcTemplate,applicationConfig,authJwtService);
+    }
+    
+    @Bean
     public HttpSessionListenerAdapter httpSessionListenerAdapter() {
         return new HttpSessionListenerAdapter();
     }

+ 3 - 21
maxkey-core/src/main/java/org/maxkey/web/WebConstants.java

@@ -25,22 +25,6 @@ package org.maxkey.web;
  */
 public class WebConstants {
 
-    public static final  String USERNAME = "username";
-
-    public static final  String REMOTE_USERNAME = "remote_username";
-
-    public static final  String CURRENT_USER = "current_user";
-
-    public static final  String CURRENT_COMPANY = "current_user_company";
-
-    public static final  String CURRENT_DEPARTMENT = "current_user_department";
-
-    public static final  String CURRENT_USER_NAVIGATIONS = "current_user_navigations";
-
-    public static final  String CURRENT_USER_ROLES = "current_user_roles";
-
-    public static final  String CURRENT_USER_SYSTEM_ROLES = "current_user_system_roles";
-
     public static final  String CURRENT_USER_PASSWORD_SET_TYPE 
                                     = "current_user_password_set_type";
 
@@ -65,15 +49,13 @@ public class WebConstants {
     public static final  String AUTHORIZE_SIGN_ON_APP_SAMLV20_ADAPTER 
                                     = "authorize_sign_on_app_samlv20_adapter";
     
-    public static final  String REMEBER_ME_SESSION = "remeber_me_session";
-
     public static final  String KERBEROS_TOKEN_PARAMETER = "kerberosToken";
 
     public static final  String CAS_SERVICE_PARAMETER = "service";
 
     public static final  String KERBEROS_USERDOMAIN_PARAMETER = "kerberosUserDomain";
 
-    public static final  String REMEBER_ME_COOKIE = "sign_in_remeber_me";
+    public static final  String REMEBER_ME_COOKIE = "sign_remeber_me";
 
     public static final  String JWT_TOKEN_PARAMETER = "jwt";
 
@@ -88,10 +70,10 @@ public class WebConstants {
     public static final  String LOGIN_ERROR_SESSION_MESSAGE 
                                     = "login_error_session_message_key";
     
-    public static final  String ONLINE_TICKET_NAME = "online_ticket";
-    
     public static final  String ONLINE_TICKET_PREFIX = "OT";
     
+    public static final  String ONLINE_TICKET_NAME = "online_ticket";
+    
 	public static final  String MXK_METADATA_PREFIX = "mxk_metadata_";
 	
     public static final class LOGIN_RESULT{

+ 0 - 6
maxkey-core/src/main/java/org/maxkey/web/WebContext.java

@@ -79,29 +79,23 @@ public final class WebContext {
         sessionAttributeNameList.add(WebConstants.AUTHORIZE_SIGN_ON_APP);
         sessionAttributeNameList.add(WebConstants.AUTHORIZE_SIGN_ON_APP_SAMLV20_ADAPTER);
         
-        sessionAttributeNameList.add(WebConstants.CURRENT_USER);
         sessionAttributeNameList.add(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE);
         
         sessionAttributeNameList.add(WebConstants.CURRENT_INST);
         
         sessionAttributeNameList.add(WebConstants.FIRST_SAVED_REQUEST_PARAMETER);
         
-        sessionAttributeNameList.add(WebConstants.REMEBER_ME_SESSION);
-        
         //logout
         logoutAttributeNameList.add(WebConstants.AUTHENTICATION);
         
         logoutAttributeNameList.add(WebConstants.AUTHORIZE_SIGN_ON_APP);
         logoutAttributeNameList.add(WebConstants.AUTHORIZE_SIGN_ON_APP_SAMLV20_ADAPTER);
         
-        logoutAttributeNameList.add(WebConstants.CURRENT_USER);
         logoutAttributeNameList.add(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE);
         
         
         logoutAttributeNameList.add(WebConstants.FIRST_SAVED_REQUEST_PARAMETER);
         
-        logoutAttributeNameList.add(WebConstants.REMEBER_ME_SESSION);
-        
     }
 
     /**

+ 33 - 23
maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/login/login.component.ts

@@ -79,27 +79,31 @@ export class UserLoginComponent implements OnInit, OnDestroy {
       this.congressLogin(this.route.snapshot.queryParams[CONSTS.CONGRESS]);
     }
 
-    if (localStorage.getItem(CONSTS.REMEMBER) && localStorage.getItem(CONSTS.REMEMBER)?.endsWith('true')) {
-      this.authenticationService.navigate({});
-      //auto auth
-    } else {
-      //init socials,state
-      this.authenticationService.clear();
-      this.authenticationService
-        .get({})
-        .pipe(
-          finalize(() => {
-            this.loading = false;
-            this.cdr.detectChanges();
-          })
-        )
-        .subscribe(res => {
-          this.loading = true;
-          if (res.code !== 0) {
-            this.error = res.msg;
-          } else {
+    //init socials,state
+    this.authenticationService.clear();
+    this.authenticationService
+      .get({ remember_me: localStorage.getItem(CONSTS.REMEMBER) })
+      .pipe(
+        finalize(() => {
+          this.loading = false;
+          this.cdr.detectChanges();
+        })
+      )
+      .subscribe(res => {
+        this.loading = true;
+        if (res.code !== 0) {
+          this.error = res.msg;
+        } else {
+          // 清空路由复用信息
+          //console.log(res.data);
+          //REMEMBER ME
+          if (res.data.token) {
             // 清空路由复用信息
-            console.log(res.data);
+            this.reuseTabService.clear();
+            // 设置用户Token信息
+            this.authenticationService.auth(res.data);
+            this.authenticationService.navigate({});
+          } else {
             this.socials = res.data.socials;
             this.state = res.data.state;
             this.captchaType = res.data.captchaType;
@@ -109,8 +113,8 @@ export class UserLoginComponent implements OnInit, OnDestroy {
               this.cdr.detectChanges();
             });
           }
-        });
-    }
+        }
+      });
     this.cdr.detectChanges();
   }
 
@@ -156,6 +160,11 @@ export class UserLoginComponent implements OnInit, OnDestroy {
   get otpCaptcha(): AbstractControl {
     return this.form.get('otpCaptcha')!;
   }
+
+  get remember(): AbstractControl {
+    return this.form.get('remember')!;
+  }
+
   // #endregion
 
   // #region get captcha
@@ -224,7 +233,8 @@ export class UserLoginComponent implements OnInit, OnDestroy {
         password: this.password.value,
         captcha: this.captcha.value,
         mobile: this.mobile.value,
-        otpCaptcha: this.otpCaptcha.value
+        otpCaptcha: this.otpCaptcha.value,
+        remeberMe: this.remember.value
       })
       .pipe(
         finalize(() => {

+ 4 - 1
maxkey-web-frontend/maxkey-web-app/src/app/service/authentication.service.ts

@@ -47,6 +47,7 @@ export class AuthenticationService {
 
   clear() {
     this.tokenService.clear();
+    localStorage.setItem(CONSTS.REMEMBER, '');
   }
 
   clearUser() {
@@ -73,7 +74,9 @@ export class AuthenticationService {
 
     this.cookieService.set(CONSTS.CONGRESS, authJwt.token);
     this.cookieService.set(CONSTS.CONGRESS, authJwt.ticket, { domain: subHostName });
-
+    if (authJwt.remeberMe) {
+      localStorage.setItem(CONSTS.REMEMBER, authJwt.remeberMe);
+    }
     this.settingsService.setUser(user);
     this.tokenService.set(authJwt);
     this.tokenService.get()?.expired;

+ 1 - 1
maxkey-web-frontend/maxkey-web-app/src/app/shared/consts.ts

@@ -1,5 +1,5 @@
 export const CONSTS = {
     CONGRESS: 'congress',
     REDIRECT_URI: 'redirect_uri',
-    REMEMBER: 'remember'
+    REMEMBER: 'remember_me'
 };

+ 45 - 12
maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/LoginEntryPoint.java

@@ -17,15 +17,21 @@
 
 package org.maxkey.web.contorller;
 
+import java.text.ParseException;
 import java.util.HashMap;
 import java.util.regex.Pattern;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.apache.commons.lang3.StringUtils;
 import org.maxkey.authn.AbstractAuthenticationProvider;
 import org.maxkey.authn.LoginCredential;
 import org.maxkey.authn.jwt.AuthJwt;
 import org.maxkey.authn.jwt.AuthJwtService;
 import org.maxkey.authn.support.kerberos.KerberosService;
+import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
+import org.maxkey.authn.support.rememberme.RemeberMe;
 import org.maxkey.authn.support.socialsignon.service.SocialSignOnProviderService;
 import org.maxkey.configuration.ApplicationConfig;
 import org.maxkey.entity.Institutions;
@@ -47,6 +53,8 @@ import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 
@@ -60,12 +68,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 public class LoginEntryPoint {
 	private static Logger _logger = LoggerFactory.getLogger(LoginEntryPoint.class);
 	
+	Pattern mobileRegex = Pattern.compile("^(13[4,5,6,7,8,9]|15[0,8,9,1,7]|188|187)\\\\d{8}$");
+	
 	@Autowired
-  	@Qualifier("authJwtService")
 	AuthJwtService authJwtService;
 	
 	@Autowired
-  	@Qualifier("applicationConfig")
   	ApplicationConfig applicationConfig;
  	
 	@Autowired
@@ -77,11 +85,9 @@ public class LoginEntryPoint {
 	SocialSignOnProviderService socialSignOnProviderService;
 	
 	@Autowired
-	@Qualifier("kerberosService")
 	KerberosService kerberosService;
 	
 	@Autowired
-	@Qualifier("userInfoService")
 	UserInfoService userInfoService;
 	
 	@Autowired
@@ -92,8 +98,8 @@ public class LoginEntryPoint {
     @Qualifier("otpAuthnService")
     protected OtpAuthnService otpAuthnService;
 	
-	Pattern mobileRegex = Pattern.compile(
-	            "^(13[4,5,6,7,8,9]|15[0,8,9,1,7]|188|187)\\\\d{8}$");
+	@Autowired
+	AbstractRemeberMeService remeberMeService;
 	
 	/**
 	 * init login
@@ -101,8 +107,28 @@ public class LoginEntryPoint {
 	 */
 	@Operation(summary  = "登录接口", description  = "用户登录地址",method="GET")
 	@RequestMapping(value={"/get"}, produces = {MediaType.APPLICATION_JSON_VALUE})
-	public ResponseEntity<?> get() {
-		_logger.debug("LoginController /get.");
+	public ResponseEntity<?> get(
+				@RequestParam(value = "remember_me", required = false) String rememberMeToken) {
+		_logger.debug("/get.");
+		//Remember Me
+		if(StringUtils.isNotBlank(rememberMeToken)
+				&& authJwtService.validateJwtToken(rememberMeToken)) {
+			try {
+				RemeberMe remeberMe = remeberMeService.resolve(rememberMeToken);
+				if(remeberMe != null) {
+					LoginCredential credential = new LoginCredential();
+					String remeberMeJwt = remeberMeService.updateRemeberMe(remeberMe);
+					credential.setUsername(remeberMe.getUsername());
+					Authentication  authentication = authenticationProvider.authenticate(credential,true);
+					if(authentication != null) {
+			 			AuthJwt authJwt = authJwtService.genAuthJwt(authentication);
+			 			authJwt.setRemeberMe(remeberMeJwt);
+			 			return new Message<AuthJwt>(authJwt).buildResponse();
+					}
+				}
+			} catch (ParseException e) {
+			}
+		}
 		//for normal login
 		HashMap<String , Object> model = new HashMap<String , Object>();
 		model.put("isRemeberMe", applicationConfig.getLoginConfig().isRemeberMe());
@@ -149,19 +175,26 @@ public class LoginEntryPoint {
  	 * @return
  	 */
  	@RequestMapping(value={"/signin"}, produces = {MediaType.APPLICATION_JSON_VALUE})
-	public ResponseEntity<?> signin( @RequestBody LoginCredential loginCredential) {
+	public ResponseEntity<?> signin( HttpServletRequest request, HttpServletResponse response,
+					@RequestBody LoginCredential credential) {
  		Message<AuthJwt> authJwtMessage = new Message<AuthJwt>(Message.FAIL);
- 		if(authJwtService.validateJwtToken(loginCredential.getState())){
- 			String authType =  loginCredential.getAuthType();
+ 		if(authJwtService.validateJwtToken(credential.getState())){
+ 			String authType =  credential.getAuthType();
  			 _logger.debug("Login AuthN Type  " + authType);
  	        if (StringUtils.isNotBlank(authType)){
-		 		Authentication  authentication = authenticationProvider.authenticate(loginCredential);	 				
+		 		Authentication  authentication = authenticationProvider.authenticate(credential);	 				
 		 		if(authentication != null) {
 		 			AuthJwt authJwt = authJwtService.genAuthJwt(authentication);
+		 			if(StringUtils.isNotBlank(credential.getRemeberMe())
+		 					&&credential.getRemeberMe().equalsIgnoreCase("true")) {
+		 				String remeberMe = remeberMeService.createRemeberMe(authentication, request, response);
+		 				authJwt.setRemeberMe(remeberMe);
+			 		}
 		 			if(WebContext.getAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE)!=null)
 		 				authJwt.setPasswordSetType(
 		 					(Integer)WebContext.getAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE));
 		 			authJwtMessage = new Message<AuthJwt>(authJwt);
+		 			
 		 		}
  	        }else {
  	        	_logger.error("Login AuthN type must eq normal , tfa or mobile . ");

+ 3 - 1
maxkey-webs/maxkey-web-maxkey/src/main/resources/application-http.properties

@@ -50,9 +50,11 @@ maxkey.server.message.queue                     =${SERVER_MESSAGE_QUEUE:none}
 #issuer name                
 maxkey.app.issuer                               =CN=ConSec,CN=COM,CN=SH
 
-maxkey.auth.jwt.expire                          =86400
 maxkey.auth.jwt.issuer                          =${maxkey.server.uri}
+maxkey.auth.jwt.expire                          =86400
 maxkey.auth.jwt.secret                          =7heM-14BtxjyKPuH3ITIm7q2-ps5MuBirWCsrrdbzzSAOuSPrbQYiaJ54AeA0uH2XdkYy3hHAkTFIsieGkyqxOJZ_dQzrCbaYISH9rhUZAKYx8tUY0wkE4ArOC6LqHDJarR6UIcMsARakK9U4dhoOPO1cj74XytemI-w6ACYfzRUn_Rn4e-CQMcnD1C56oNEukwalf06xVgXl41h6K8IBEzLVod58y_VfvFn-NGWpNG0fy_Qxng6dg8Dgva2DobvzMN2eejHGLGB-x809MvC4zbG7CKNVlcrzMYDt2Gt2sOVDrt2l9YqJNfgaLFjrOEVw5cuXemGkX1MvHj6TAsbLg
+maxkey.auth.jwt.refresh.expire                  =86400
+maxkey.auth.jwt.refresh.secret                  =7heM-14BtxjyKPuH3ITIm7q2-ps5MuBirWCsrrdbzzSAOuSPrbQYiaJ54AeA0uH2XdkYy3hHAkTFIsieGkyqxOJZ_dQzrCbaYISH9rhUZAKYx8tUY0wkE4ArOC6LqHDJarR6UIcMsARakK9U4dhoOPO1cj74XytemI-w6ACYfzRUn_Rn4e-CQMcnD1C56oNEukwalf06xVgXl41h6K8IBEzLVod58y_VfvFn-NGWpNG0fy_Qxng6dg8Dgva2DobvzMN2eejHGLGB-x809MvC4zbG7CKNVlcrzMYDt2Gt2sOVDrt2l9YqJNfgaLFjrOEVw5cuXemGkX1MvHj6TAsbLg
 ############################################################################
 #Login configuration                                                       #
 ############################################################################