我正在使用spring security 3.1.4而我正在尝试创建一个使用数据库来保存开放会话的服装会话注册表。
我将此SessionRegistryImpl实现用作参考:https://github.com/spring-projects/spring-security/blob/master/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java
这是我的实施:
@Component
public class ClusteredSessionRegistryImpl implements SessionRegistry, ApplicationListener<SessionDestroyedEvent> {
@Autowired
private PrincipalRepository principalRepository;
@Autowired
private SessionIdRepository sessionIdRepository;
public List<Object> getAllPrincipals() {
return new ArrayList<Object>(
this.principalRepository.findAllPrincipals());
}
public List<SessionInformation> getAllSessions(Object principal, boolean includeExpiredSessions) {
final Set<String> sessionsUsedByPrincipal = this.principalRepository.findByPrincipal(
principal).getSessionsUsedByPrincipal();
if (sessionsUsedByPrincipal == null) {
return Collections.emptyList();
}
List<SessionInformation> list = new ArrayList<SessionInformation>(
sessionsUsedByPrincipal.size());
for (String sessionId : sessionsUsedByPrincipal) {
SessionInformation sessionInformation = getSessionInformation(sessionId);
if (sessionInformation == null) {
continue;
}
if (includeExpiredSessions || !sessionInformation.isExpired()) {
list.add(sessionInformation);
}
}
return list;
}
public SessionInformation getSessionInformation(String sessionId) {
Assert.hasText(
sessionId,
"SessionId required as per interface contract");
SessionId sessionIdDoc = this.sessionIdRepository.findBySessionId(sessionId);
if (sessionIdDoc == null)
return null;
return sessionIdDoc.getSessionInformation();
}
public void onApplicationEvent(SessionDestroyedEvent event) {
String sessionId = event.getId();
removeSessionInformation(sessionId);
}
public void refreshLastRequest(String sessionId) {
Assert.hasText(
sessionId,
"SessionId required as per interface contract");
SessionInformation info = getSessionInformation(sessionId);
if (info != null) {
info.refreshLastRequest();
}
}
public void registerNewSession(String sessionId, Object principal) {
Assert.hasText(
sessionId,
"SessionId required as per interface contract");
Assert.notNull(
principal,
"Principal required as per interface contract");
if (getSessionInformation(sessionId) != null) {
removeSessionInformation(sessionId);
}
this.sessionIdRepository.save(new SessionId(
sessionId, new SessionInformation(
principal, sessionId, new Date())));
Principal principalDoc = this.putIfAbsent(principal);
Set<String> sessionsUsedByPrincipal = principalDoc.getSessionsUsedByPrincipal();
if (sessionsUsedByPrincipal == null) {
sessionsUsedByPrincipal = new CopyOnWriteArraySet<String>();
}
sessionsUsedByPrincipal.add(sessionId);
principalDoc.setSessionsUsedByPrincipal(sessionsUsedByPrincipal);
this.principalRepository.save(principalDoc);
}
public void removeSessionInformation(String sessionId) {
Assert.hasText(
sessionId,
"SessionId required as per interface contract");
SessionInformation info = getSessionInformation(sessionId);
if (info == null) {
return;
}
SessionId sessionIdDoc = this.sessionIdRepository.findBySessionId(sessionId);
if (sessionIdDoc == null) {
return;
}
this.sessionIdRepository.delete(sessionIdDoc);
Set<String> sessionsUsedByPrincipal = this.principalRepository.findByPrincipal(
info.getPrincipal()).getSessionsUsedByPrincipal();
if (sessionsUsedByPrincipal == null) {
return;
}
sessionsUsedByPrincipal.remove(sessionId);
if (sessionsUsedByPrincipal.isEmpty()) {
Principal principalDoc = this.principalRepository.findByPrincipal(info.getPrincipal());
this.principalRepository.delete(principalDoc);
}
else {
Principal principalDoc = this.principalRepository.findByPrincipal(info.getPrincipal());
principalDoc.setSessionsUsedByPrincipal(sessionsUsedByPrincipal);
this.principalRepository.save(principalDoc);
}
}
private Principal putIfAbsent(Object principal) {
Principal principalDoc = this.principalRepository.findByPrincipal(principal);
if (principalDoc == null) {
return this.principalRepository.save(new Principal(
principal, null));
}
else {
return principalDoc;
}
}
}
my security xml:
<security:http use-expressions="true" auto-config="false"
entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/player/login"
access="permitAll" />
<security:custom-filter position="FORM_LOGIN_FILTER"
ref="twoFactorAuthenticationFilter" />
<security:intercept-url pattern="/**"
access="isAuthenticated()" />
<security:logout logout-url="/player/logout"
success-handler-ref="playerLogoutSuccessHandler" />
<security:session-management>
<security:concurrency-control
max-sessions="1" session-registry-ref="clusteredSessionRegistryImpl"
error-if-maximum-exceeded="true" />
</security:session-management>
</security:http>
<bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/demo/player/login" />
</bean>
<bean id="twoFactorAuthenticationFilter" class="com.xxx.filter.TwoFactorAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureHandler" ref="failureHandler" />
<property name="authenticationSuccessHandler" ref="playerAuthenticationSuccessHandler" />
<property name="postOnly" value="true" />
<property name="extraParameter" value="domain" />
</bean>
<bean id="failureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login?login_error=true" />
</bean>
<bean id="bCryptPasswordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="authenticationProvider">
</security:authentication-provider>
</security:authentication-manager>
</beans>
问题是它永远不会进入public void registerNewSession(String sessionId, Object principal)
所以db中没有保存任何内容。
编辑: 我从authenticationSuccessHandler中添加了对registerNewSession()的调用,这是一个合法的解决方案吗?
我的新问题是max-sessions =“1”不起作用,我可以打开超过1个会话。 (我覆盖了我校长的等号和哈希码)