Apache Shiro: authenticate with username/password but store user id as the principal

StackOverflow https://stackoverflow.com/questions/21966703

  •  15-10-2022
  •  | 
  •  

Pergunta

I'm getting started with Apache Shiro. I've started with simple examples and have been building up complexity as I go.

Currently I'm collecting the email address and password from the login form with JSF and using a UsernamePasswordToken to authenticate the user with Shiro.

UsernamePasswordToken token = new UsernamePasswordToken(email, password);
SecurityUtils.getSubject().login(token);

The is backed by the out of the box JDBC realm with a simple query

jdbcRealm.authenticationQuery = SELECT password FROM user WHERE email = ?

To get further details about the user, such as their name I'm looking up the user in the database by the principal - which is their email address.

currentUser = userDAO.findByEmail((String) SecurityUtils.getSubject().getPrincipal());

This works well, but the user is allowed to change their email address, which will break the lookup. My goal is to store the unique user id as the principal rather than the email address as this can never change. How would I go about achieving this?

Foi útil?

Solução

I ended up solving this problem with a simple approach - do the conversion from the email address to the user id before creating the authentication token, and use the user id as the principal in the token.

try{
    // Lookup the user by email
    User user = userDAO.findByEmail(email);

    // If no match we can't authenticate
    if(user == null){
        throw new AuthenticationException();
    }

    // Else, build a token with the user id and password
    UsernamePasswordToken token = new UsernamePasswordToken(user.getUserId().toString(), password);

    // Attempt to login
    SecurityUtils.getSubject().login(token);

}catch(AuthenticationException ex){
    return false;
}

My UserDAO bean is configured to handle javax.persistence.NoResultException's and return null.

In my shiro.ini file I have changed the jdbcRealm.authenticationQuery to the following (note I'm using MySQL)

jdbcRealm.authenticationQuery = SELECT password FROM user WHERE user_id = CAST(? AS UNSIGNED)

Finally, to look up details about the user I'm now looking up by the user id, which is now the principal.

currentUser = userDAO.findByUserId(Integer.parseInt((String) SecurityUtils.getSubject().getPrincipal()));
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top