提交 25e1904c 编写于 作者: M MaxKey

SessionManager optimize

上级 7354f805
......@@ -65,7 +65,7 @@ tomcatembedloggingjuliVersion =8.5.2
springVersion =5.3.20
springBootVersion =2.6.7
springSecurityVersion =5.6.3
springDataVersion =2.6.2
springDataVersion =2.6.4
springSessionVersion =2.6.3
springkafkaVersion =2.8.2
springretryVersion =1.3.0
......
......@@ -124,7 +124,8 @@ public abstract class AbstractAuthenticationRealm {
historyLogin.setSessionId(WebContext.genId());
historyLogin.setSessionStatus(7);
Authentication authentication = (Authentication ) WebContext.getAttribute(WebConstants.AUTHENTICATION);
if(authentication.getPrincipal() instanceof SignPrincipal) {
if(authentication != null
&& authentication.getPrincipal() instanceof SignPrincipal) {
historyLogin.setSessionStatus(1);
historyLogin.setSessionId(userInfo.getSessionId());
}
......
......@@ -21,6 +21,7 @@ import org.maxkey.authn.realm.AbstractAuthenticationRealm;
import org.maxkey.authn.realm.ldap.LdapAuthenticationRealm;
import org.maxkey.authn.realm.ldap.LdapAuthenticationRealmService;
import org.maxkey.constants.ConstsLoginType;
import org.maxkey.constants.ConstsStatus;
import org.maxkey.entity.ChangePassword;
import org.maxkey.entity.PasswordPolicy;
import org.maxkey.entity.UserInfo;
......@@ -100,15 +101,21 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm {
if(ldapAuthenticationRealmService != null) {
//passwordMatches == false and ldapSupport ==true
//validate password with LDAP
LdapAuthenticationRealm ldapRealm = ldapAuthenticationRealmService.getByInstId(userInfo.getInstId());
if(!passwordMatches && ldapRealm != null && ldapRealm.isLdapSupport()) {
passwordMatches = ldapRealm.passwordMatches(userInfo, password);
if(passwordMatches) {
//write password to database Realm
ChangePassword changePassword = new ChangePassword(userInfo);
changePassword.setPassword(password);
userInfoService.changePassword(changePassword, false);
}
try {
LdapAuthenticationRealm ldapRealm = ldapAuthenticationRealmService.getByInstId(userInfo.getInstId());
if(!passwordMatches && ldapRealm != null
&& ldapRealm.isLdapSupport()
&& userInfo.getIsLocked() == ConstsStatus.ACTIVE) {
passwordMatches = ldapRealm.passwordMatches(userInfo, password);
if(passwordMatches) {
//write password to database Realm
ChangePassword changePassword = new ChangePassword(userInfo);
changePassword.setPassword(password);
userInfoService.changePassword(changePassword, false);
}
}
}catch(Exception e) {
_logger.debug("passwordvalid Exception : {}" , e);
}
}
_logger.debug("passwordvalid : {}" , passwordMatches);
......
......@@ -66,7 +66,11 @@ public class LdapAuthenticationRealm extends AbstractAuthenticationRealm{
username = userInfo.getWindowsAccount();
}
_logger.debug("Attempting to authenticate {} at {}", username, ldapServer);
isAuthenticated= ldapServer.authenticate(username, password);
try {
isAuthenticated = ldapServer.authenticate(username, password);
}catch(Exception e) {
_logger.debug("Attempting Authenticated fail .");
}
if (isAuthenticated ) {
return true;
}
......
/*
* 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.session;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.time.LocalTime;
import java.util.Date;
import java.util.List;
import org.maxkey.entity.HistoryLogin;
import org.maxkey.entity.UserInfo;
import org.maxkey.util.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class AbstractSessionManager implements SessionManager{
private static Logger _logger = LoggerFactory.getLogger(AbstractSessionManager.class);
protected JdbcTemplate jdbcTemplate;
protected int validitySeconds = 60 * 30; //default 30 minutes.
private static final String DEFAULT_DEFAULT_SELECT_STATEMENT =
"select id,sessionid,userId,username,displayname,logintime from mxk_history_login where sessionstatus = 1";
private static final String LOGOUT_USERINFO_UPDATE_STATEMENT =
"update mxk_userinfo set lastlogofftime = ? , online = " + UserInfo.ONLINE.OFFLINE + " where id = ?";
private static final String HISTORY_LOGOUT_UPDATE_STATEMENT =
"update mxk_history_login set logouttime = ? ,sessionstatus = 7 where sessionid = ?";
@Override
public List<HistoryLogin> querySessions() {
List<HistoryLogin> listSessions = jdbcTemplate.query(
DEFAULT_DEFAULT_SELECT_STATEMENT,
new OnlineTicketRowMapper());
return listSessions;
}
public void profileLastLogoffTime(String userId,String lastLogoffTime) {
_logger.trace("userId {} , lastlogofftime {}" ,userId, lastLogoffTime);
jdbcTemplate.update( LOGOUT_USERINFO_UPDATE_STATEMENT,
new Object[] { lastLogoffTime, userId },
new int[] { Types.TIMESTAMP, Types.VARCHAR });
}
public void sessionLogoff(String sessionId,String lastLogoffTime) {
_logger.trace("sessionId {} , lastlogofftime {}" ,sessionId, lastLogoffTime);
jdbcTemplate.update(HISTORY_LOGOUT_UPDATE_STATEMENT,
new Object[] { lastLogoffTime, sessionId },
new int[] { Types.VARCHAR, Types.VARCHAR });
}
@Override
public void terminate(String onlineTicket,String userId,String username) {
String lastLogoffTime = DateUtils.formatDateTime(new Date());
_logger.trace("{} user {} terminate Ticket {} ." ,lastLogoffTime,username, onlineTicket);
this.profileLastLogoffTime(userId, lastLogoffTime);
this.sessionLogoff(onlineTicket, lastLogoffTime);
remove(onlineTicket);
}
private final class OnlineTicketRowMapper implements RowMapper<HistoryLogin> {
@Override
public HistoryLogin mapRow(ResultSet rs, int rowNum)
throws SQLException {
HistoryLogin history=new HistoryLogin();
history.setId(rs.getString(1));
history.setSessionId(rs.getString(2));
history.setUserId(rs.getString(3));
history.setUsername(rs.getString(4));
history.setDisplayName(rs.getString(5));
history.setLoginTime(rs.getString(6));
return history;
}
}
@Override
public void create(String sessionId, Session session) {
}
@Override
public Session remove(String sessionId) {
return null;
}
@Override
public Session get(String sessionId) {
return null;
}
@Override
public Session refresh(String sessionId, LocalTime refreshTime) {
return null;
}
@Override
public Session refresh(String sessionId) {
return null;
}
@Override
public void setValiditySeconds(int validitySeconds) {
}
}
......@@ -19,28 +19,30 @@ package org.maxkey.authn.session;
import java.time.Duration;
import java.time.LocalTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.maxkey.entity.HistoryLogin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemorySessionManager extends AbstractSessionManager{
public class InMemorySessionManager implements SessionManager{
private static final Logger _logger = LoggerFactory.getLogger(InMemorySessionManager.class);
protected int validitySeconds = 60 * 30; //default 30 minutes.
protected static Cache<String, Session> sessionStore =
Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(2000000)
.build();
public InMemorySessionManager(JdbcTemplate jdbcTemplate,int validitySeconds) {
public InMemorySessionManager(int validitySeconds) {
super();
this.jdbcTemplate = jdbcTemplate;
sessionStore =
Caffeine.newBuilder()
.expireAfterWrite(validitySeconds, TimeUnit.SECONDS)
......@@ -67,16 +69,6 @@ public class InMemorySessionManager extends AbstractSessionManager{
return session;
}
@Override
public void setValiditySeconds(int validitySeconds) {
sessionStore =
Caffeine.newBuilder()
.expireAfterWrite(validitySeconds, TimeUnit.SECONDS)
.maximumSize(200000)
.build();
}
@Override
public Session refresh(String sessionId,LocalTime refreshTime) {
Session session = get(sessionId);
......@@ -101,4 +93,16 @@ public class InMemorySessionManager extends AbstractSessionManager{
return session;
}
@Override
public List<HistoryLogin> querySessions() {
// TODO Auto-generated method stub
return null;
}
@Override
public void terminate(String sessionId, String userId, String username) {
// TODO Auto-generated method stub
}
}
......@@ -19,17 +19,20 @@ package org.maxkey.authn.session;
import java.time.Duration;
import java.time.LocalTime;
import java.util.List;
import org.maxkey.entity.HistoryLogin;
import org.maxkey.persistence.redis.RedisConnection;
import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
public class RedisSessionManager extends AbstractSessionManager {
public class RedisSessionManager implements SessionManager {
private static final Logger _logger = LoggerFactory.getLogger(RedisSessionManager.class);
protected int validitySeconds = 60 * 30; //default 30 minutes.
RedisConnectionFactory connectionFactory;
public static String PREFIX="REDIS_SESSION_";
......@@ -43,10 +46,9 @@ public class RedisSessionManager extends AbstractSessionManager {
*/
public RedisSessionManager(
RedisConnectionFactory connectionFactory,
JdbcTemplate jdbcTemplate,int validitySeconds) {
int validitySeconds) {
super();
this.connectionFactory = connectionFactory;
this.jdbcTemplate = jdbcTemplate;
this.validitySeconds = validitySeconds;
}
......@@ -118,5 +120,17 @@ public class RedisSessionManager extends AbstractSessionManager {
return session;
}
@Override
public List<HistoryLogin> querySessions() {
// TODO Auto-generated method stub
return null;
}
@Override
public void terminate(String sessionId, String userId, String username) {
// TODO Auto-generated method stub
}
}
......@@ -33,8 +33,6 @@ public interface SessionManager {
public Session refresh(String sessionId ,LocalTime refreshTime);
public Session refresh(String sessionId);
public void setValiditySeconds(int validitySeconds);
public List<HistoryLogin> querySessions();
......
......@@ -17,33 +17,149 @@
package org.maxkey.authn.session;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.time.LocalTime;
import java.util.Date;
import java.util.List;
import org.maxkey.constants.ConstsPersistence;
import org.maxkey.entity.HistoryLogin;
import org.maxkey.entity.UserInfo;
import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.maxkey.util.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class SessionManagerFactory {
public class SessionManagerFactory implements SessionManager{
private static final Logger _logger =
LoggerFactory.getLogger(SessionManagerFactory.class);
public SessionManager getManager(
int persistence,
private static final String DEFAULT_DEFAULT_SELECT_STATEMENT =
"select id,sessionid,userId,username,displayname,logintime from mxk_history_login where sessionstatus = 1";
private static final String LOGOUT_USERINFO_UPDATE_STATEMENT =
"update mxk_userinfo set lastlogofftime = ? , online = " + UserInfo.ONLINE.OFFLINE + " where id = ?";
private static final String HISTORY_LOGOUT_UPDATE_STATEMENT =
"update mxk_history_login set logouttime = ? ,sessionstatus = 7 where sessionid = ?";
private JdbcTemplate jdbcTemplate;
private InMemorySessionManager inMemorySessionManager;
private RedisSessionManager redisSessionManager;
private boolean isRedis = false;
public SessionManagerFactory(int persistence,
JdbcTemplate jdbcTemplate,
RedisConnectionFactory redisConnFactory,
int validitySeconds){
SessionManager sessionService = null;
if (persistence == ConstsPersistence.INMEMORY) {
sessionService = new InMemorySessionManager(jdbcTemplate,validitySeconds);
_logger.debug("InMemorySessionManager");
} else if (persistence == ConstsPersistence.JDBC) {
_logger.debug("JdbcSessionService not support ");
} else if (persistence == ConstsPersistence.REDIS) {
sessionService = new RedisSessionManager(
redisConnFactory,jdbcTemplate,validitySeconds);
_logger.debug("RedisSessionManager");
int validitySeconds) {
this.jdbcTemplate = jdbcTemplate;
this.inMemorySessionManager =
new InMemorySessionManager(validitySeconds);
_logger.debug("InMemorySessionManager");
if (persistence == ConstsPersistence.REDIS) {
isRedis = true;
this.redisSessionManager =
new RedisSessionManager(redisConnFactory,validitySeconds);
_logger.debug("RedisSessionManager");
}
}
public void create(String sessionId, Session session) {
inMemorySessionManager.create(sessionId, session);
if(isRedis) {
redisSessionManager.create(sessionId, session);
}
}
public Session remove(String sessionId) {
Session session = inMemorySessionManager.remove(sessionId);
if(isRedis) {
session = redisSessionManager.remove(sessionId);
}
return session;
}
public Session get(String sessionId) {
Session session = inMemorySessionManager.get(sessionId);
if(session == null && isRedis) {
session = redisSessionManager.get(sessionId);
}
return session;
}
public Session refresh(String sessionId, LocalTime refreshTime) {
Session session = null;
if(isRedis) {
session = redisSessionManager.refresh(sessionId,refreshTime);
//renew one
inMemorySessionManager.create(sessionId, session);
}else {
session = inMemorySessionManager.refresh(sessionId,refreshTime);
}
return session;
}
public Session refresh(String sessionId) {
Session session = null;
if(isRedis) {
session = redisSessionManager.refresh(sessionId);
//renew one
inMemorySessionManager.create(sessionId, session);
}else {
session = inMemorySessionManager.refresh(sessionId);
}
return sessionService;
return session;
}
public List<HistoryLogin> querySessions() {
List<HistoryLogin> listSessions = jdbcTemplate.query(
DEFAULT_DEFAULT_SELECT_STATEMENT,
new OnlineTicketRowMapper());
return listSessions;
}
private void profileLastLogoffTime(String userId,String lastLogoffTime) {
_logger.trace("userId {} , lastlogofftime {}" ,userId, lastLogoffTime);
jdbcTemplate.update( LOGOUT_USERINFO_UPDATE_STATEMENT,
new Object[] { lastLogoffTime, userId },
new int[] { Types.TIMESTAMP, Types.VARCHAR });
}
private void sessionLogoff(String sessionId,String lastLogoffTime) {
_logger.trace("sessionId {} , lastlogofftime {}" ,sessionId, lastLogoffTime);
jdbcTemplate.update(HISTORY_LOGOUT_UPDATE_STATEMENT,
new Object[] { lastLogoffTime, sessionId },
new int[] { Types.VARCHAR, Types.VARCHAR });
}
public void terminate(String sessionId, String userId, String username) {
String lastLogoffTime = DateUtils.formatDateTime(new Date());
_logger.trace("{} user {} terminate Ticket {} ." ,lastLogoffTime,username, sessionId);
this.profileLastLogoffTime(userId, lastLogoffTime);
this.sessionLogoff(sessionId, lastLogoffTime);
this.remove(sessionId);
}
private final class OnlineTicketRowMapper implements RowMapper<HistoryLogin> {
@Override
public HistoryLogin mapRow(ResultSet rs, int rowNum)
throws SQLException {
HistoryLogin history=new HistoryLogin();
history.setId(rs.getString(1));
history.setSessionId(rs.getString(2));
history.setUserId(rs.getString(3));
history.setUsername(rs.getString(4));
history.setDisplayName(rs.getString(5));
history.setLoginTime(rs.getString(6));
return history;
}
}
}
......@@ -204,7 +204,7 @@ public class AuthenticationAutoConfiguration implements InitializingBean {
) {
_logger.trace("session timeout " + timeout);
SessionManager sessionManager =
new SessionManagerFactory().getManager(
new SessionManagerFactory(
persistence, jdbcTemplate, redisConnFactory,timeout);
return sessionManager;
}
......
......@@ -222,10 +222,12 @@ public class PasswordPolicyValidator {
public void lockUser(UserInfo userInfo) {
try {
if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
jdbcTemplate.update(LOCK_USER_UPDATE_STATEMENT,
new Object[] { ConstsStatus.LOCK, new Date(), userInfo.getId() },
new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
userInfo.setIsLocked(ConstsStatus.LOCK);
if(userInfo.getIsLocked() == ConstsStatus.ACTIVE) {
jdbcTemplate.update(LOCK_USER_UPDATE_STATEMENT,
new Object[] { ConstsStatus.LOCK, new Date(), userInfo.getId() },
new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
userInfo.setIsLocked(ConstsStatus.LOCK);
}
}
} catch (Exception e) {
_logger.error("lockUser Exception",e);
......@@ -263,6 +265,7 @@ public class PasswordPolicyValidator {
new Object[] { 0, ConstsStatus.ACTIVE, new Date(), userInfo.getId() },
new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.VARCHAR });
userInfo.setIsLocked(ConstsStatus.ACTIVE);
userInfo.setBadPasswordCount(0);
}
} catch (Exception e) {
_logger.error("resetAttempts Exception",e);
......@@ -288,7 +291,12 @@ public class PasswordPolicyValidator {
if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
userInfo.setBadPasswordCount(userInfo.getBadPasswordCount() + 1);
setBadPasswordCount(userInfo.getId(),userInfo.getBadPasswordCount());
PasswordPolicy passwordPolicy = passwordPolicyRepository.getPasswordPolicy();
if(userInfo.getBadPasswordCount() + 1 >= passwordPolicy.getAttempts()) {
_logger.debug("Bad Password Count {} , Max Attempts {}",
userInfo.getBadPasswordCount() + 1,passwordPolicy.getAttempts());
this.lockUser(userInfo);
}
}
}
......
......@@ -21,5 +21,5 @@ export const CONSTS = {
REDIRECT_URI: 'redirect_uri',
REMEMBER: 'remember_me',
TOKEN: '_token',
VERSION: 'v3.5.0 GA'
VERSION: 'v3.5.1 GA'
};
......@@ -19,5 +19,5 @@ export const CONSTS = {
INST: 'inst',
REDIRECT_URI: 'redirect_uri',
REMEMBER: 'remember',
VERSION: 'v3.5.0 GA'
VERSION: 'v3.5.1 GA'
};
#端口号
application:
name: maxkey-gateway-server
formatted-version: v3.5.0 GA
formatted-version: v3.5.1 GA
server:
port: 9000
spring:
......@@ -12,17 +12,17 @@ spring:
routes:
#nacos健康检查端口8080
- id: maxkeys_route
uri: lb://maxkey
uri: lb://sign
filters:
- PrefixPath=/
predicates:
- Path=/maxkey/**
- Path=/sign/**
- id: maxkey_mgts_route
uri: lb://maxkey-mgt
uri: lb://maxkey-mgt-api
filters:
- PrefixPath=/
predicates:
- Path=/maxkey-mgt/**
- Path=/maxkey-mgt-api/**
# default-filters:
# - name: Hystrix
# args:
......
......@@ -18,7 +18,7 @@
application.title =MaxKey
#for dynamic service discovery
spring.application.name =maxkey-monitor
application.formatted-version =v3.5.0 GA
application.formatted-version =v3.5.1 GA
#nacos discovery
spring.cloud.nacos.discovery.enabled =${NACOS_DISCOVERY_ENABLED:false}
spring.cloud.nacos.discovery.instance-enabled =false
......
......@@ -16,7 +16,7 @@
#MaxKey Title and Version #
############################################################################
application.title =MaxKey
application.formatted-version =v3.5.0 GA
application.formatted-version =v3.5.1 GA
#for dynamic service discovery
spring.application.name =maxkey
############################################################################
......
......@@ -16,7 +16,7 @@
#MaxKey Title and Version #
############################################################################
application.title =MaxKey-Mgt
application.formatted-version =v3.5.0 GA
application.formatted-version =v3.5.1 GA
#for dynamic service discovery
spring.application.name =maxkey-mgt
############################################################################
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册