spring 安全从数据库中获取用户 ID
spring security get user id from DB
我正在使用 spring 安全性进行身份验证,并且能够在我需要的任何地方成功获得 User
对象 (org.springframework.security.core.userdetails.User
)。
但我也想要 UserId
,spring 的 User
对象中没有。所以我创建了自己的对象(com.app.site.pojo.User
)。它有一些额外的变量,如 userId、用户出生日期 等。现在我希望 spring 安全使用我的 user
对象而不是 spring User
对象。它应该包含有关该用户的所有详细信息。
我试图将用户对象类型转换为我的对象,它抛出异常(很明显)。
我不想再次进行数据库调用以再次从数据库中获取用户 ID。
如何实现?
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="customUserDetailsService" />
</bean>
customUserDetailsService 将覆盖 loadUserByUsername,如下所示
@Override
public UserDetails loadUserByUsername(String username) {
return customUser;
// where customUser extends org.springframework.security.core.userdetails.User
}
您可以在 customUser 下拥有自定义字段
我和你的情况一样,我做的是在登录后将用户重定向到一个新页面,并创建该页面的控制器函数,从数据库中获取用户并存储他的 id 作为 会话变量。
@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 的新手,所以我不确定这是否是最好的方法。
更好的方法是创建一个 UserDetaisService,returns 一个扩展您的对象类型并实现 UserDetails 的对象。这意味着您只需要执行一次数据库查找。
通过让 loadUserByUsername 的结果实现 UserDetails 并扩展您的用户对象,您可以将其称为自定义用户对象,Spring 安全性可以将其称为 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;
}
}
然后您可以在配置中引用自定义 UserDetailsService。例如:
<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 README also reference the recorded webinar.
中找到有关此内容的详细信息
@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();
}
我正在使用 spring 安全性进行身份验证,并且能够在我需要的任何地方成功获得 User
对象 (org.springframework.security.core.userdetails.User
)。
但我也想要 UserId
,spring 的 User
对象中没有。所以我创建了自己的对象(com.app.site.pojo.User
)。它有一些额外的变量,如 userId、用户出生日期 等。现在我希望 spring 安全使用我的 user
对象而不是 spring User
对象。它应该包含有关该用户的所有详细信息。
我试图将用户对象类型转换为我的对象,它抛出异常(很明显)。
我不想再次进行数据库调用以再次从数据库中获取用户 ID。
如何实现?
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="customUserDetailsService" />
</bean>
customUserDetailsService 将覆盖 loadUserByUsername,如下所示
@Override
public UserDetails loadUserByUsername(String username) {
return customUser;
// where customUser extends org.springframework.security.core.userdetails.User
}
您可以在 customUser 下拥有自定义字段
我和你的情况一样,我做的是在登录后将用户重定向到一个新页面,并创建该页面的控制器函数,从数据库中获取用户并存储他的 id 作为 会话变量。
@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 的新手,所以我不确定这是否是最好的方法。
更好的方法是创建一个 UserDetaisService,returns 一个扩展您的对象类型并实现 UserDetails 的对象。这意味着您只需要执行一次数据库查找。
通过让 loadUserByUsername 的结果实现 UserDetails 并扩展您的用户对象,您可以将其称为自定义用户对象,Spring 安全性可以将其称为 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;
}
}
然后您可以在配置中引用自定义 UserDetailsService。例如:
<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 README also reference the recorded webinar.
中找到有关此内容的详细信息@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();
}