Spring Security从数据库获取用户ID

use*_*305 5 java authentication spring spring-mvc spring-security

我使用 spring security 进行身份验证,并成功地能够在我需要的任何地方获取User对象 ( org.springframework.security.core.userdetails.User) 。

但我UserId也想要,这在 spring 的对象中不存在User。所以我创建了我自己的对象(com.app.site.pojo.User)。它有一些额外的变量,如userId用户出生日期等。现在我希望 spring security 使用我的user对象而不是 springUser对象。它应该包含有关该用户的所有详细信息。

我尝试将用户对象类型转换为我的对象,它抛出异常(很明显)。

我不想再次进行数据库调用以再次从数据库获取用户ID。

我怎样才能实现它?

Rob*_*nch 6

更好的方法是创建一个 UserDetaisService,它返回一个扩展您的 Object 类型并实现 UserDetails 的对象。这意味着您只需要执行一次数据库查找。

通过让 loadUserByUsername 的结果实现 UserDetails 并扩展您的 User 对象,您可以将其称为自定义用户对象,并且 Spring Security 可以将其称为 UserDetails。

例如:

@Service
public class UserRepositoryUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    @Autowired
    public UserRepositoryUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        User user = userRepository.findByEmail(username);
        if(user == null) {
            throw new UsernameNotFoundException("Could not find user " + username);
        }
        return new UserRepositoryUserDetails(user);
    }

    private final static class UserRepositoryUserDetails extends User implements UserDetails {

        private UserRepositoryUserDetails(User user) {
            super(user);
        }

        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return AuthorityUtils.createAuthorityList("ROLE_USER");
        }

        @Override
        public String getUsername() {
            return getEmail();
        }

        @Override
        public boolean isAccountNonExpired() {
            return true;
        }

        @Override
        public boolean isAccountNonLocked() {
            return true;
        }

        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }

        @Override
        public boolean isEnabled() {
            return true;
        }

        private static final long serialVersionUID = 5639683223516504866L;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在配置中引用自定义 UserDetailsS​​ervice。例如:

<security:authentication-manager>
  <security:authentication-provider user-service-ref="customUserDetails" />
</security:authentication-manager>
<bean id="customUserDetails" class="sample.UserRepositoryUserDetailsService"/>
Run Code Online (Sandbox Code Playgroud)

如果您使用 Spring Security 3.2.x+,您可以使用 Spring Security 的@AuthenticationPrincipal来解析自定义用户对象。例如:

@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser) {

    // .. find messags for this user and return them ...
}
Run Code Online (Sandbox Code Playgroud)

否则您可以使用以下内容:

@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(Authentication auth) {
        User customUser = (User) auth.getPrincipal();
     ...
}
Run Code Online (Sandbox Code Playgroud)

如果使用 XML 配置,您将需要向 Spring MVC 注册 AuthenticationPrincipalArgumentResolver。

<mvc:annotation-driven>
  <mvc:argument-resolvers>
    <beans:bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver"/>
  </mvc:argument-resolvers>
</mvc:annotation-driven>
Run Code Online (Sandbox Code Playgroud)

您可以在我的github 示例项目中找到有关此内容的详细信息。自述文件还引用了录制的网络研讨会


小智 2

我的情况和你一样,我所做的就是在登录后将用户重定向到一个新页面,并创建该页面的控制器函数,以从数据库获取用户并将其id存储为Session Variable

    @RequestMapping(value = { "/overview" }, method = RequestMethod.GET)
    public ModelAndView overViewPage(HttpServletRequest request) {

        ModelAndView model = new ModelAndView();
        model.addObject("title", "Spring Security + Hibernate Example");
        model.addObject("message", "This is default page!");
        model.setViewName("hello");


        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        UserDetails userDetail = (UserDetails) auth.getPrincipal();

        User u = userService.getUser(userDetail.getUsername());
        request.getSession().setAttribute("userId", u.getId());

        return model;

    }
Run Code Online (Sandbox Code Playgroud)

您可以使用用户对象或仅使用他的id进行将来的查询

int userId = (int) request.getSession().getAttribute("userId");
Run Code Online (Sandbox Code Playgroud)

我的userService只是一个简单的服务

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sports.dao.UserDao;

@Service
@Transactional
public class UserServiceImpl implements UserService{

    @Autowired
    private UserDao userDao;

    public com.sports.models.User getUser(String username){
        return userDao.findByUserName(username);
    }

}
Run Code Online (Sandbox Code Playgroud)

我也是春天的新手,所以我不确定这是否是最好的方法。