【问题标题】:spring security get user id from DBspring security从数据库获取用户ID
【发布时间】:2015-06-02 08:15:19
【问题描述】:

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

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

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

我不想再次调用 DB 来再次从 DB 中获取 userId。

我该如何实现?

【问题讨论】:

    标签: java spring spring-mvc authentication spring-security


    【解决方案1】:
    @RequestMapping(value="/getLogedUserid")
    public Long getUserByUsername(HttpServletRequest httpServletRequest) {      
        HttpSession httpSession = httpServletRequest.getSession();
        SecurityContext securityContext = (SecurityContext)
                httpSession.getAttribute("SPRING_SECURITY_CONTEXT");
        String username = securityContext.getAuthentication().getName();
        return userMetier.getUserByUsername(username);
    }
    

    这里我们定义了通过用户名获取 id 的函数

        @Override
    public Long getUserByUsername(String Username) {
        User user = userRepository.getUserByUsername(Username);
    
        return user.getIdUser();
    }
    

    【讨论】:

      【解决方案2】:

      更好的方法是创建一个 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;
          }
      }
      

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

      <security:authentication-manager>
        <security:authentication-provider user-service-ref="customUserDetails" />
      </security:authentication-manager>
      <bean id="customUserDetails" class="sample.UserRepositoryUserDetailsService"/>
      

      如果您使用的是 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 ...
      }
      

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

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

      如果使用 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>
      

      您可以在我的github sample project 中找到有关此的详细信息。自述文件还引用了the recorded webinar

      【讨论】:

      • 我无法让它工作。我在视图方法中的 CustomUser 为空。如果我使用 UserDetails 它可以工作,但我需要一个 CustomUser 实例。我正在使用 Spring Security 4.0.1.RELEASE
      • 已修复:这是因为我的 OAuth 配置正在使用我的用户存储库,但 WebSecurityConfigurerAdapter 为我的测试定义在 MemoryAuthentication 中。
      【解决方案3】:

      我和你的情况一样,我所做的就是在用户登录后将用户重定向到一个新页面,并创建该页面的控制器功能,以从数据库中获取用户并存储他的 id em> 作为会话变量

          @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;
      
          }
      

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

      int userId = (int) request.getSession().getAttribute("userId");
      

      我的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);
          }
      
      }
      

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

      【讨论】:

        【解决方案4】:
        <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
          <property name="userDetailsService" ref="customUserDetailsService" />
        </bean>
        

        customUserDetailsS​​ervice 将覆盖 loadUserByUsername,如下所示

        @Override
        public UserDetails loadUserByUsername(String username) {
        return customUser;
        // where customUser extends org.springframework.security.core.userdetails.User
        }
        

        您可以在 customUser 下拥有自定义字段

        【讨论】:

        • 如果我们可以使用注释做一些事情会更好,如果你能提供一些例子,那就太好了。
        猜你喜欢
        • 2015-07-21
        • 2013-11-29
        • 2014-05-05
        • 1970-01-01
        • 2021-01-23
        • 2015-12-06
        • 1970-01-01
        • 2011-01-19
        • 2014-09-18
        相关资源
        最近更新 更多