All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.beangle.security.session.jdbc.DBSessionRegistry.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2005, The Beangle Software.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package org.beangle.security.session.jdbc

import org.beangle.commons.cache.CacheManager
import org.beangle.commons.concurrent.Timers
import org.beangle.commons.io.BinarySerializer
import org.beangle.commons.lang.Objects
import org.beangle.jdbc.query.ParamSetter
import org.beangle.security.authc.Account
import org.beangle.security.session.*

import java.sql.{Timestamp, Types}
import java.time.Instant
import javax.sql.DataSource

/** 基于数据库的session注册表
 * 使用数据库的$sessionTable表
 */
class DBSessionRegistry(domainProvider: DomainProvider, dataSource: DataSource, cacheManager: CacheManager, serializer: BinarySerializer)
  extends DBSessionRepo(domainProvider, dataSource, cacheManager, serializer)
    with SessionRegistry {

  private val insertColumns = "id,principal,description,ip,agent,os,login_at,last_access_at,tti_seconds,category_id,domain_id,data"

  override def init(): Unit = {
    super.init()
    Timers.start("Beangle Session", flushInterval, accessReporter, new DBSessionCleaner(this))
  }

  override def register(sessionId: String, info: Account, agent: Session.Agent, profile: SessionProfile): Session = {
    val existed = get(sessionId).orNull
    val principal = info.getName
    if (profile.checkCapacity) {
      val sc = sessionCount(info.categoryId)
      if (sc + 1 > profile.capacity) {
        throw new OvermaxSessionException(profile.capacity, principal)
      }
    }
    // 是否为重复注册
    if (null != existed && Objects.equals(existed.principal, principal)) {
      existed
    } else {
      if (null != existed) remove(sessionId, " expired by replacement."); // 注销同会话的其它账户
      if (profile.checkConcurrent && profile.concurrent > 0) {
        val concurrents = findByPrincipal(principal)
        val expiredCnt = concurrents.size + 1 - profile.concurrent
        if (expiredCnt > 0) {
          concurrents.take(expiredCnt) foreach (x => expire(x.id))
        }
      }
      val session = builder.build(sessionId, info, Instant.now, agent, profile.ttiSeconds) // 新生
      save(session)
      publish(new LoginEvent(session))
      session
    }
  }

  override def findExpired(): collection.Seq[String] = {
    executor.query(s"select id from $sessionTable info where add_seconds(info.last_access_at,tti_seconds) <= current_timestamp and domain_id=?", this.domainId)
      .map { data => data(0).toString }
  }

  private def sessionCount(categoryId: Int): Int = {
    executor.queryForInt(s"select count(*) from $sessionTable where category_id=" + categoryId + " and domain_id=" + domainId).getOrElse(0)
  }

  override def remove(sessionId: String, reason: String): Option[Session] = {
    val s = get(sessionId)
    s foreach { session =>
      evict(sessionId)
      executor.update(s"delete from $sessionTable where id=?", sessionId)
      publish(new LogoutEvent(session, reason))
    }
    s
  }

  private def save(s: Session): Unit = {
    val sessionId = s.id
    val ac = s.agent
    executor.statement(s"insert into $sessionTable ($insertColumns) values(?,?,?,?,?,?,?,?,?,?,?,?)")
      .prepare(x => {
        x.setString(1, sessionId)
        x.setString(2, s.principal.getName)
        x.setString(3, s.principal.asInstanceOf[Account].description)
        x.setString(4, ac.ip)
        x.setString(5, ac.name)
        x.setString(6, ac.os)
        x.setTimestamp(7, Timestamp.from(s.loginAt))
        x.setTimestamp(8, Timestamp.from(s.loginAt))
        x.setInt(9, s.ttiSeconds)
        x.setInt(10, s.principal.asInstanceOf[Account].categoryId)
        x.setInt(11, domainId)
        ParamSetter.setParam(x, 12, serializer.asBytes(s), Types.BINARY)
      }).execute()
    put(s)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy