2015-05-19 8 views
-1

У меня проблема с моим классом входа. Если пользователь безуспешно пытается войти в систему с именем пользователя, то учетная запись пользователя должна быть отключена. Во время выполнения ошибок нет, но в моей базе данных ничего не меняется. Я что-то делаю неправильно с обновлением моей базы данных через Hibernate, я думал, что могу просто использовать свой UserBean.class для доступа к свойствам, изменения их и последующей транзакции Hibernate?Почему транзакция Hibernate не обновляет мою базу данных?

Вот мой LoginDAO.class:

package com.sga.app.dao; 

import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.PreparedStatement; 
import java.sql.SQLException; 
import java.util.ArrayList; 
import java.util.List; 

import org.apache.log4j.Logger; 
import org.hibernate.Criteria; 
import org.hibernate.FlushMode; 
import org.hibernate.Session; 
import org.hibernate.context.internal.ManagedSessionContext; 
import org.hibernate.criterion.Restrictions; 
import org.owasp.encoder.Encode; 
import org.springframework.context.ApplicationListener; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.security.access.AccessDeniedException; 
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; 
import org.springframework.security.core.userdetails.UsernameNotFoundException; 
import org.springframework.stereotype.Component; 
import org.springframework.transaction.annotation.Transactional; 
import org.springframework.validation.BindingResult; 

import com.sga.app.beans.UserBean; 
import com.sga.app.hibernate.HibernateUtil; 
import com.sga.app.security.LoginFailureEventListener; 
import com.sga.app.security.XssRequestWrapper; 

@Component("loginDAO") 
@Transactional 
@Configuration 
public class LoginDAO implements 
    ApplicationListener<AuthenticationFailureBadCredentialsEvent> { 

private int loginAttemptsThreshold; 
private int failedLoginAttempts; 
private static Logger logger = Logger 
     .getLogger(LoginFailureEventListener.class); 
private static Session session; 
private Criteria criteria; 
private String username; 
private boolean enabled; 
private String forename; 
private String authority; 
private XssRequestWrapper xssReqWrapper; 
private PreparedStatement prepStmtUsers; 
private PreparedStatement prepStmtAuthorities; 
private String URL = "jdbc:oracle:thin:system/[email protected]:1521/XE"; 
private String updateUsersStatement = "insert into users (username, password) 
    values (:username, :password)"; 
private String updateAuthoritiesStatement = "insert into authorities (username, 
    authority) values (:username, :authority)"; 

@Bean 
public LoginDAO loginDAO() { 
    return new LoginDAO(); 
} 

public void setLoginAttemptsThreshold(int threshold) { 
    this.loginAttemptsThreshold = threshold; 
} 

@Transactional 
public void loginUser(UserBean user, BindingResult result) { 

    try { 
     Connection conn = DriverManager.getConnection(URL); 
     // clean out any possible XSS injection 
     String cleanUsernameValueInput = cleanOutXSSVulnerabilities("j_username"); 
     String cleanPasswordValueInput = cleanOutXSSVulnerabilities("j_password"); 
     // OWASP encoding 
     String safeUsername = Encode.forHtml(cleanUsernameValueInput); 
     prepStmtUsers.setString(1, safeUsername); 
     String safePassword = Encode.forHtml(cleanPasswordValueInput); 
     prepStmtUsers.setString(2, safePassword); 
     prepStmtAuthorities.setString(1, safeUsername); 
     String safeUserAuthority = Encode.forHtml(user.getAuthority()); 
     prepStmtAuthorities.setString(2, safeUserAuthority); 
     // execute login process 
     prepStmtUsers = conn.prepareStatement(updateUsersStatement); 
     prepStmtAuthorities = conn 
       .prepareStatement(updateAuthoritiesStatement); 
     prepStmtUsers.executeUpdate(); 
     prepStmtAuthorities.executeUpdate(); 
     conn.close(); 
    } catch (SQLException e) { 
     e.printStackTrace(); 
    } catch (AccessDeniedException accessDenied) { 
     accessDenied.printStackTrace(); 
    } 
} 

private String cleanOutXSSVulnerabilities(String input) { 
    return xssReqWrapper.cleanXSS(input); 
} 

@Override 
public void onApplicationEvent(
     AuthenticationFailureBadCredentialsEvent event) { 
    if (event.getException().getClass() 
      .equals(UsernameNotFoundException.class)) { 
     return; 
    } 
    // print registration attempts to log file for security investigation if 
    // required 
    logger.info("Registration attempt failed: " + event.getException()); 
    logger.info("Registration attempt number: " + event.getTimestamp()); 
    String userId = event.getAuthentication().getName(); 
    logger.info("FAILED LOGIN ATTEMPT NUMBER " 
      + recordLoginAttempts(userId)); 
    recordLoginAttempts(userId); 
    if (recordLoginAttempts(userId) >= loginAttemptsThreshold) { 
     lockoutUser(userId); 
    } 
} 

private int recordLoginAttempts(String userId) { 
    failedLoginAttempts++; 
    return failedLoginAttempts; 
} 

@SuppressWarnings("unchecked") 
private ArrayList<UserBean> getUserAccountDetails(String input) { 
    ArrayList<UserBean> returnValues = new ArrayList<UserBean>(); 
    session = HibernateUtil.createSessionFactory().openSession(); 
    session.setFlushMode(FlushMode.MANUAL); 
    ManagedSessionContext.bind(session); 
    session.beginTransaction(); 
    criteria = session.createCriteria(UserBean.class); 
    List<UserBean> retrievedUser = criteria.add(
      Restrictions.like("username", input)).list(); 
    for (UserBean userDetails : retrievedUser) { 
     logger.debug("USERNAME INSIDE THE GET USER ACCOUNT DETAILS METHOD: " 
       + userDetails.getUsername()); 
     logger.debug("AUTHORITY INSIDE THE GET USER ACCOUNT DETAILS METHOD: " 
       + userDetails.getAuthority()); 
     returnValues.add(userDetails); 
    } 
    session.flush(); 
    session.getTransaction().commit(); 
    session.close(); 
    return returnValues; 
} 

private void lockoutUser(String userId) { 
    ArrayList<UserBean> userAccountValues = getUserAccountDetails(userId); 
    session = HibernateUtil.createSessionFactory().openSession(); 
    session.setFlushMode(FlushMode.MANUAL); 
    ManagedSessionContext.bind(session); 
    session.beginTransaction(); 
    for (UserBean user : userAccountValues) { 
     username = user.getUsername(); 
     forename = user.getForename(); 
     enabled = user.getEnabled(); 
     authority = user.getAuthority(); 
     logger.debug("USERNAME: " + username); 
     logger.debug("FORENAME: " + forename); 
     logger.debug("ENABLED BEFORE CHANGE: " + enabled); 
     user.setEnabled(false); 
     logger.debug("AUTHORITY BEFORE CHANGE: " + authority); 
     user.setAuthority("BLOCKED"); 
    } 
    session.flush(); 
    session.getTransaction().commit(); 
    logger.debug("ENABLED AFTER CHANGE: " + enabled); 
    logger.debug("AUTHORITY AFTER CHANGE: " + authority); 
    session.close(); 
    ManagedSessionContext.unbind(HibernateUtil.createSessionFactory()); 
    } 

} 
+0

Первоначально я вызвал onApplicationEvent() в моем loginUser(), если result.hasErrors() в попытке вызвать процесс блокировки, но никаких обновлений базы данных не было. – smoggers

+0

С кодом очень много. Вы смешиваете проблемы, вы пытаетесь использовать '@ Transactional', но очень сильно работаете в своем коде, чтобы сделать это невозможным. Для начала не смешивайте '@ Configuration' и' @ Component' (который должен быть '@ Repository' imho), это разные проблемы и не должны находиться в одном классе. Вы используете весну и управление транзакциями, поэтому пусть весна делает тяжелую работу вместо «getCurrentSession». –

+0

Ваш код также ошибочен, так как вы сохраняете состояние (т. Е. 'FailLoginAttempts'), если у вас есть 10 пользователей, каждый из которых пытается войти в систему, а один из них сразу же заблокируется, так как этот счетчик является общим. Я не уверен, чего вы пытаетесь достичь с этим классом, но я бы сначала предложил вам прочитать, как Spring может помочь вам и очистить ваш класс. –

ответ

1

Я не думаю, что вы должны называть openSession таким образом. Я настоятельно рекомендую вам переписать метод, чтобы вообще не выполнять какую-либо «сессионную» работу. Пусть Spring справится с этим, тем более, что вы уже используете @Transactional.

В любом случае, в методе lockoutUser() пользователи, которых вы находите, не привязаны к сеансу, который создается после него.

ArrayList<UserBean> userAccountValues = getUserAccountDetails(userId); session = HibernateUtil.createSessionFactory().openSession();

Таким образом, позже в методе при обновлении пользовательских экземпляров этой ArrrayList, сессия не понимает, что экземпляры пользователей должны быть сохранены, потому что сессия никогда не была их отслеживания.

Попробуйте иметь только одну сессию в потоке. Каждый метод может иметь свою собственную транзакцию, но мы редко сталкиваемся с ситуациями, когда нам требуется более одного сеанса в потоке. Кажется, это не такая ситуация.

1
session.flush(); 
session.getTransaction().commit(); 
session.close(); 

Попытка удалить session.flush(); или положить его после session.getTransaction().commit(); может работать.

+1

Не знаете, в чем смысл делать флеш после фиксации. Но я согласен, что флеш не нужен, если совершение совершается. – Mecon

-2

Не похоже, что вы звоните session.save(Object) или session.update(Object).

Смежные вопросы