rememberme

This commit is contained in:
MaxKey
2022-04-29 11:58:05 +08:00
parent 8db33b0e8d
commit 5f0f1fa7e0
16 changed files with 550 additions and 72 deletions

View File

@@ -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() {

View File

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

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}