středa 23. ledna 2008

Acegi - logujeme loginy

Používáte-li pro správu přístupu k vaší webové aplikaci framework Acegi, možná se vám bude hodit zaznamenávat uživatelské přístupy (platné loginy) někam do databáze. Zde je jeden ze způsobů jak se s tímto problémem vypořádat. Následující přiklad používá Hibernate a databázi Oracle.

Nejdříve si připravím vlastní metodu pro zápis do databáze v DAO. Umístím ji do třídy cz.mujpackage.dao.UserDao, která rozšiřuje org.springframework.orm.hibernate3.support.HibernateDaoSupport a poskytuje metody pro správu uživatelů, rolí, apod. Pro zvýšení výkonu použiji v Hibernate SQLQuery namísto vytváření instance třídy modelu a jejího ukládání pomocí metody save(...).

/**
* Adds log entry to table AUTH_LOG (Oracle database form - pk_sequence has to be configured)
* @param aName username
* @param aRemoteAddress remote address of request
*/
public void logAuthenticationSuccess(final String aName, final String aRemoteAddress) {
  final HibernateCallback callback = new HibernateCallback() {
    public Object doInHibernate(final Session session) throws HibernateException {
      return session
        .createSQLQuery("insert into AUTH_LOG (id, datum, user, address)" +
            " values (pk_sequence.nextval, sysdate, :user, :address)")
        .setParameter("user", aName)
        .setParameter("address", aRemoteAddress)
        .executeUpdate();
    }
  };
  getHibernateTemplate().execute(callback);
}

Nyní přijde hlavní část a to zachycení události, která je vyvolána při úspěšném přihlášení uživatele do systému. Vytvořím tedy implementaci interfejsu org.springframework.context.ApplicationListener a budu obsluhovat události typu InteractiveAuthenticationSuccessEvent.

package cz.mujpackage.acegi;

import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.util.Assert;

import cz.mujpackage.dao.UserDao;


/**
* Logs the successful authentication to database table
* @author Josef Cacek
*/
public class MyAuthListener implements ApplicationListener, InitializingBean {

  protected final Log log = LogFactory.getLog(getClass());

  private UserDao userDao;

  /**
   * Writes entry to AUTH_LOG table when InteractiveAuthenticationSuccessEvent comes
   * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
   */
  public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof InteractiveAuthenticationSuccessEvent) {
             final Authentication tmpAuth = SecurityContextHolder.getContext().getAuthentication();
             log.debug("InteractiveAuthenticationSuccessEvent: " + tmpAuth.getName());
             if (tmpAuth.getDetails() instanceof WebAuthenticationDetails) {
               final WebAuthenticationDetails webDetails =
                 (WebAuthenticationDetails) tmpAuth.getDetails();
               userDao.logAuthenticationSuccess(tmpAuth.getName(),webDetails.getRemoteAddress());
             } else {
               log.warn("Authentication.getDetails() not instance of WebAuthenticationDetails: "
                   + tmpAuth.getDetails());
             }
        }
    }

  /**
   * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
   */
  public void afterPropertiesSet() throws Exception {
    Assert.notNull(userDao);
  }

  /**
   * @return the userDao
   */
  public UserDao getUserDao() {
    return userDao;
  }

  /**
   * @param userDao the userDao to set
   */
  public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
  }

}

Teď už zbývá pouze nakonfigurovat beanu v applicationContext.xml a je hotovo:

<bean id="myAuthListener" class="cz.mujpackage.acegi.MyAuthListener">
    <property name="userDao" ref="userDao"/>
</bean>

A jak by řekl Forrest Gump

....a to je asi tak vše, co vím o krevetách

2 komentáře:

radovan řekl(a)...

Moc diky za clanek, velmi mi pomohl.

Josef Cacek řekl(a)...

Jsem rád, když Javlog pomáhá vyřešit problémy, se kterými se občas sám potýkám. :-)