web-dev-qa-db-fra.com

Ajout de détails supplémentaires à l'objet principal stocké dans le contexte de sécurité Spring

J'utilise Spring 3.0 et Spring Security 3. Je peux authentifier un utilisateur par rapport à une base de données à l'aide de Spring Security. En utilisant:

SecurityContextHolder.getContext().getAuthentication().getPrincipal()

Je peux récupérer le nom d'utilisateur de l'utilisateur actuellement connecté. Je souhaite ajouter des détails supplémentaires comme l'ID utilisateur et le module accède à l'objet principal stocké dans le contexte Spring Security afin de pouvoir le récupérer plus tard. Comment puis-je ajouter des détails supplémentaires à l'objet principal, puis comment le récupérer plus tard sur une classe jsp ou Java. Veuillez fournir un extrait de code approprié si possible.

Edit: j'utilise JDBC pour accéder à ma base de données.

Merci d'avance.

33
newUser

Afin d'ajouter plus de détails à l'utilisateur authentifié. Vous devez d'abord créer votre propre implémentation de l'objet User qui devrait étendre l'objet User de sécurité Spring. Après cela, vous pouvez ajouter les propriétés que vous souhaitez ajouter à l'utilisateur authentifié. Une fois cela fait, vous devez renvoyer votre implémentation de l'objet utilisateur dans UserDetailService (si vous n'utilisez pas LDAP pour l'authentification). Ce lien fournit les détails pour ajouter plus de détails à l'utilisateur authentifié -

http://javahotpot.blogspot.in/2013/12/spring-security-adding-more-information.html

23
Yogen

Voici ce dont vous avez besoin:

  1. Étendre le ressort User (org.springframework.security.core.userdetails.User) et les propriétés dont vous avez besoin.
  2. Étendre le ressort UserDetailsService (org.springframework.security.core.userdetails.UserDetailsService) et remplissez l'objet ci-dessus. Remplacez loadUserByUsername et renvoyez votre classe d'utilisateurs étendue
  3. Définissez votre UserDetailsService personnalisé dans AuthenticationManagerBuilder

Par exemple

public class CurrentUser extends User{

   //This constructor is a must
    public CurrentUser(String username, String password, boolean enabled, boolean accountNonExpired,
            boolean credentialsNonExpired, boolean accountNonLocked,
            Collection<? extends GrantedAuthority> authorities) {
        super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
    }
    //Setter and getters are required
    private String firstName;
    private String lastName;

}

Les détails utilisateur personnalisés peuvent être:

@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {

    //Try to find user and its roles, for example here we try to get it from database via a DAO object
   //Do not confuse this foo.bar.User with CurrentUser or spring User, this is a temporary object which holds user info stored in database
    foo.bar.User user = userDao.findByUserName(username);

    //Build user Authority. some how a convert from your custom roles which are in database to spring GrantedAuthority
    List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRole());

    //The magic is happen in this private method !
    return buildUserForAuthentication(user, authorities);

}


//Fill your extended User object (CurrentUser) here and return it
private User buildUserForAuthentication(foo.bar.User user, 
List<GrantedAuthority> authorities) {
    String username = user.getUsername();
    String password = user.getPassword();
    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

    return new CurrentUser(username, password, enabled, accountNonExpired, credentialsNonExpired,
            accountNonLocked, authorities);
   //If your database has more information of user for example firstname,... You can fill it here 
  //CurrentUser currentUser = new CurrentUser(....)
  //currentUser.setFirstName( user.getfirstName() );
  //.....
  //return currentUser ;
}

private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {

    Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

    // Build user's authorities
    for (UserRole userRole : userRoles) {
        setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
    }

    return new ArrayList<GrantedAuthority>(setAuths);
}

}

Configurer le contexte de sécurité Spring

@Configuration
@EnableWebSecurity
@PropertySource("classpath://configs.properties")
public class SecurityContextConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("userDetailsService")
    private UserDetailsService userDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

Tout est fini!

Tu peux appeler (CurrentUser)getAuthentication().getPrincipal() pour vous obtenir récemment CurrentUser ou définir certaines propriétés.

13
Alireza Fattahi

(Je suppose que vous disposez d'une configuration de base de Spring Security et que vous savez comment les composants de base fonctionnent ensemble)

La manière la plus "correcte" serait de fournir votre propre implémentation de AuthenticationProvider , qui renvoie une implémentation personnalisée Authentication . Ensuite, vous pouvez remplir cette instance Authentication avec tout ce dont vous avez besoin. Par exemple:

public class MyAuthentication extends UsernamePasswordAuthenticationToken implements Authentication {

    public MyAuthentication(Object principal, Object credentials, int moduleCode) {
        super(principal, credentials);
        this.moduleCode = moduleCode;
    }

    public MyAuthentication(Object principal, Object credentials,  Collection<? extends GrantedAuthority> authorities,int moduleCode) {
        super(principal, credentials, authorities);
        this.moduleCode = moduleCode;
    }

    private int moduleCode;

    public getModuleCode() {
        return moduleCode;
    }   
}


public class MyAuthenticationProvider extends DaoAuthenticationProvider {

    private Collection<GrantedAuthority> obtainAuthorities(UserDetails user) {
        // return granted authorities for user, according to your requirements
    }

    private int obtainModuleCode(UserDetails user) {
        // return moduleCode for user, according to your requirements
    }

    @Override
    public Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {
        // Suppose this user implementation has a moduleCode property
        MyAuthentication result = new MyAuthentication(authentication.getPrincipal(),
                                                       authentication.getCredentials(),
                                                       obtainAuthorities(user),
                                                       obtainModuleCode(user));
        result.setDetails(authentication.getDetails());
        return result;
    }
}

Et puis, dans applicationContext.xml:

<authentication-manager>
    <authentication-provider ref="myAuthenticationProvider">
</authentication-manager>

<bean id="myAuthenticationProvider" class="MyAuthenticationProvider" scope="singleton">
    ...
</bean>

Je suppose que vous pourriez le faire fonctionner en fournissant des implémentations personnalisées de AuthenticationDetails et AuthenticationDetailsSource , mais je pense que ce serait une approche moins propre .

11
gpeche

La "seule" chose que vous devez faire est de créer votre propre implémentation serDetailsService qui renvoie votre propre implémentation d'un objet serDetails .

Voir ici pour un tutoriel qui implémente un UserDetailsService basé sur JPA.

4
M. Deinum