Java 向存储在spring安全上下文中的主体对象添加其他详细信息

Java 向存储在spring安全上下文中的主体对象添加其他详细信息,java,spring,spring-security,Java,Spring,Spring Security,我正在使用Spring3.0和SpringSecurity3。我能够使用Spring安全性根据数据库对用户进行身份验证。使用: SecurityContextHolder.getContext().getAuthentication().getPrincipal() 我能够检索当前登录用户的用户名。我希望添加额外的细节,比如用户id和对存储在Spring安全上下文中的主体对象的模块访问,以便以后检索它。如何向主体对象添加额外的细节,然后如何在稍后的jsp或java类中检索它。如果可能,请提供适

我正在使用Spring3.0和SpringSecurity3。我能够使用Spring安全性根据数据库对用户进行身份验证。使用:

SecurityContextHolder.getContext().getAuthentication().getPrincipal()
我能够检索当前登录用户的用户名。我希望添加额外的细节,比如用户id和对存储在Spring安全上下文中的主体对象的模块访问,以便以后检索它。如何向主体对象添加额外的细节,然后如何在稍后的jsp或java类中检索它。如果可能,请提供适当的代码段

编辑:我正在使用JDBC访问我的数据库

提前感谢。

(我假设您有一个基本的Spring安全配置,并且知道这些基本组件是如何协同工作的)

最“正确”的方法是提供您自己的实现,返回自定义实现。然后,您可以在这个
身份验证
实例中填写所需的所有内容。例如:

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;
    }
}
我想您可以通过提供和的自定义实现来实现它,但我认为这是一种不太干净的方法。

您需要做的“唯一”事情是创建您自己的实现,它返回您自己的对象实现


有关实现基于JPA的
userdetails服务的教程,请参见,以便为经过身份验证的用户添加更多详细信息。您需要首先创建自己的用户对象实现,它应该扩展SpringSecurity用户对象。之后,您可以添加要添加到已验证用户的属性。完成后,您需要返回UserDetailService中用户对象的实现(如果您没有使用LDAP进行身份验证)。此链接提供向已验证用户添加更多详细信息的详细信息--

以下是您需要的:

  • 扩展spring
    User
    org.springframework.security.core.userdetails.User
    )类以及您需要的任何属性
  • 扩展spring
    UserDetailsService
    org.springframework.security.core.userdetails.UserDetailsService
    )并填充上述对象。重写
    loadUserByUsername
    并返回扩展的用户类
  • AuthenticationManagerBuilder
  • 比如说

    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;
    
    }
    
    都做完了


    您可以调用
    (CurrentUser)getAuthentication().getPrincipal()
    来获取新的
    CurrentUser
    或设置一些属性。

    创建您自己的
    UserDetails
    实现和您自己的
    UserDetailsService
    实现。有了它,你可以做任何你想做的事。添加您想要的属性等,谢谢。我一直在尝试做同样的事情,但我认为我做错了什么@Deinum你能不能给我一个代码片段,在那里它已经成功地实现了。我正在使用JDBC连接到数据库。你能指定我在教程中必须做的更改吗,因为它是基于JPA的。当我重写UserDetailsService的loadUserByUsername(字符串用户名)时,我不确定如何使用JDBC处理失败的身份验证请求。你能帮我吗?为什么你需要处理失败的身份验证请求?Spring为您做到了这一点,当您实现自己的
    UserDetailsService
    时,这一点不会改变。例如,当用户名和密码不匹配时,当我重写该方法时,我应该如何处理该情况。在这种情况下,我应该只返回一个null对象吗?您不需要处理它,spring security会为您处理它。
    UserDetailsService
    仅用于查找用户,不用于检查密码。正如您所注意到的,只有一个方法
    loadUserByUsername
    方法的名称说明了一切,方法的属性也是一样,没有密码,那么您如何验证密码?!您还可以在示例链接的LoginService中发布loadUserDetails(用户名)的实现吗。我想知道如何处理失败的身份验证请求。提前感谢仅在提及的链接上回答..您的博客链接并没有完全回答问题,正如植入LoginService所要求的那样。通常你应该在这个网站上回答这个问题,而不是在你的博客上引用文章。如果你不使用LDAP进行身份验证,为什么要这么说?此解决方案不适用于LDAP吗?因为使用此服务,您需要将密码返回到spring,并且无法从LDAP读取密码。。相反,要使用LDAP,您可以实现AuthenticationProvider这是可行的,但是当服务器重新启动时,我们会遇到现有会话的问题:java.lang.ClassCastException:be.storefront.imicloud.security.MyUserDetails不能转换为be.storefront.imicloud.security.MyUserDetails。这应该如何处理?@Wouter请问一个关于完整堆栈跟踪的不同问题!解决方案很好,但请确保不要将
    (CurrentUser)getAuthentication().getPrincipal()
    强制转换到无需身份验证即可访问的控制器/服务方法中。因为
    anonymous
    将由
    getAuthentication().getPrincipal()
    返回,因此
    ClassCastException:java.lang.String不能转换为com.sample.CurrentUser
    当您直接更改DBs上的其他参数(如“firstname”上面的参数)时,我发现这很危险,持久性框架仍然显示以前的值…@w对于上面的示例,当“//Setter和getter上的属性是必需的”和“//If您的数据库有更多的用户信息,例如firstname,…您可以在这里填充“不符时,会发生强制转换异常。
    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;
    
    }
    
    @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);
    }
    
    }
    
    @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);
        }