如何使用 Spring Boot 使用 LDAP 登录从数据库中获取用户角色
How to fetch user role from DB using LDAP login using Spring Boot
您好,我是 Spring 引导和 LDAP 的新手。我遇到了问题!
我可以通过 LDAP 登录,但我无法获取存储在我的数据库中的用户角色。我确实收到以下错误:
org.springframework.security.ldap.userdetails.LdapUserDetailsImpl cannot be cast to com.test.rnd.geo.web.dto.CustomUser
我试过这个:
private CustomUser getUserDetails() {
CustomUser userDetails = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
LOGGER.info("Deatils: "+userDetails);
LOGGER.info("UserName: " + userDetails.getUsername());
LOGGER.info("Auth Token: " + userDetails.getAuthToken());
LOGGER.info("User Role size: " + userDetails.getAuthorities().size());
LOGGER.info("User Role : " + userDetails.getAuthorities());
return userDetails;
}
我在获取此 getUserDetails() 函数时遇到错误。
CustomUser customUser = getUserDetails();
这是我的自定义用户 Class:
@Component
@Scope("session")
public class CustomUser implements UserDetails {
private String username;
private String password;
private List<RoleEntity> authorities;
private String authToken;
public String getAuthToken() {
return authToken;
}
public void setAuthToken(String authToken) {
this.authToken = authToken;
}
public void setAuthorities(List<RoleEntity> authorities) {
this.authorities = authorities;
}
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "CustomUser{" +
"username='" + username + '\'' +
", password='****" + '\'' +
", authorities=" + authorities +
", AuthToken='" + authToken + '\'' +
'}';
}
}
这是我的 WebSecurityConfig:
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(customAuthenticationProvider)
.ldapAuthentication()
.userSearchFilter("(&(mail={0})(memberOf=CN=aa,OU=Security Group,OU=aa,DC=aa,DC=com))")
.contextSource()
.url("ldap://www.domain.com:3268/dc=v,dc=com")
.managerDn("aaa")
.managerPassword("aaa");
}
存储库Class:
@Repository
public class UserAuthRepository {
@Autowired
private InterServiceConnector serviceConnector;
@Autowired
private httpsServiceConnector httpsServiceConnector;
private static final org.slf4j.Logger LOG
= LoggerFactory.getLogger(CustomAuthenticationProvider.class);
@Value("${dmzAddress}")
private String host;
public CustomUser authenticateUser(String userName, String password) {
CustomUser customUser = null;
try {
customUser = null;
LOG.info("UserAuthRepository::authenticateUser:: userName" + userName);
// LOG.info("UserAuthRepository::authenticateUser:: password ********");
Request request = new Request();
request.setUsername(userName);
request.setPassword(password);
Gson gson = new GsonBuilder().create();
String jsonInput = gson.toJson(request);
// LOG.info("UserAuthRepository::authenticateUser:: Authentication Token :: " + request.getAuthToken());
String user = null;
if (host.contains("http://")){
user = serviceConnector.serviceCall(jsonInput, "portalLogin", "post", request.getAuthToken());
}
else{
user = httpsServiceConnector.serviceCall(jsonInput, "portalLogin", "post");
}
// String user = serviceConnector.serviceCall(jsonInput, "portalLogin", "post", request.getAuthToken());
// String user = httpsServiceConnector.serviceCall(jsonInput, "portalLogin", "post");
// LOG.info("UserAuthRepository::authenticateUser:: user---->>> " + user);
customUser = gson.fromJson(user, CustomUser.class);
LOG.info("UserAuthRepository:: Custom User:: {}", customUser);
} catch (JsonSyntaxException e) {
LOG.error("UserAuthRepository :: authenticateUser :: Parse Exception", e);
}
return customUser;
}
}
首先,您的 CustomUser 应该实现 LdapUserDetails
而不是 UserDetails
您还需要 subclass LdapUserDetailsMapper
因为 Spring 将调用 mapUserFromContext
并且您可以在此处从数据库中获取所需的任何数据并创建一个CustomUser 的实例。
@Component
public class CustomLdapUserDetailsMapper extends LdapUserDetailsMapper {
@Autowired
private IUserRepository userRepository;
@Autowired
private IUserRoleRepository userRoleRepository;
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<? extends GrantedAuthority> authorities) {
User user = userRepository.findOneByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("Username not found");
}
UserDetails userDetails = super.mapUserFromContext(ctx, username, getAuthorities(user));
//add a constructor for your CustomUser
return new CustomUser(user.getEmail(), user.getFullName(), (LdapUserDetails) userDetails);
}
}
private Set<GrantedAuthority> getAuthorities(User user) {
Set<GrantedAuthority> authorities = new HashSet<>();
//populate authorities/user roles from User (db entity) and UserRole entities
for (UserRole userRole : userRoleRepository.findAllByUserId(user.getId())) {
authorities.add(new SimpleGrantedAuthority(userRole.getRole.getName()));
}
return authorities;
}
}
最后,告诉您的身份验证提供商使用此 ldap 映射器 class(将其放入您的网络安全代码中)
@Autowired
private CustomLdapUserDetailsMapper customLdapUserDetailsMapper;
....
customAuthenticationProvider.setUserDetailsContextMapper(customLdapUserDetailsMapper);
更新:CustomUser 代码可能看起来像这样
public class CustomUser implements LdapUserDetails{
private String email;
private String fullName;
private String username;
private LdapUserDetails ldapUserDetails;
public CustomUser(String email, String fullName, LdapUserDetails ldapUserDetails) {
super();
this.email = email;
this.fullName = fullName;
this.ldapUserDetails = ldapUserDetails;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return ldapUserDetails.getAuthorities();
}
@Override
public String getPassword() {
return ldapUserDetails.getPassword();
}
@Override
public String getUsername() {
return ldapUserDetails.getUsername();
}
//add all the other overrides and getter/setter methods
}
存储库 classes 可能类似于
public interface IUserRepository extends JpaRepository<User, Integer> {
public User findOneByUsername(String username);
public User findOneById(Integer id);
public User findOneByEmail(String email);
}
public interface IUserRoleRepository extends JpaRepository<UserRole, Integer> {
UserRole findOneByRoleName(String rolename);//role name like admin, user, mod etc
UserRole findOneById(Integer id);//role id
}
@dsp_user给出了很好的解决方案。
现在,根据您上面的代码,我假设您正在使用存储库 Class 中的一个函数,该函数将用户名和密码作为参数。
做类似的另一个功能,只接受用户名作为参数。在您的 CustomLdapUserDetailsMapper Class.
中调用该函数
试试这个代码:
@Component
public class CustomLdapUserDetailsMapper extends LdapUserDetailsMapper {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
CustomUser user = userRepository.authenticationMethod(username);
if (user == null) {
throw new UsernameNotFoundException("User is not found!");
}
return user;
}
}
我希望这能解决问题。
您好,我是 Spring 引导和 LDAP 的新手。我遇到了问题!
我可以通过 LDAP 登录,但我无法获取存储在我的数据库中的用户角色。我确实收到以下错误:
org.springframework.security.ldap.userdetails.LdapUserDetailsImpl cannot be cast to com.test.rnd.geo.web.dto.CustomUser
我试过这个:
private CustomUser getUserDetails() {
CustomUser userDetails = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
LOGGER.info("Deatils: "+userDetails);
LOGGER.info("UserName: " + userDetails.getUsername());
LOGGER.info("Auth Token: " + userDetails.getAuthToken());
LOGGER.info("User Role size: " + userDetails.getAuthorities().size());
LOGGER.info("User Role : " + userDetails.getAuthorities());
return userDetails;
}
我在获取此 getUserDetails() 函数时遇到错误。
CustomUser customUser = getUserDetails();
这是我的自定义用户 Class:
@Component
@Scope("session")
public class CustomUser implements UserDetails {
private String username;
private String password;
private List<RoleEntity> authorities;
private String authToken;
public String getAuthToken() {
return authToken;
}
public void setAuthToken(String authToken) {
this.authToken = authToken;
}
public void setAuthorities(List<RoleEntity> authorities) {
this.authorities = authorities;
}
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "CustomUser{" +
"username='" + username + '\'' +
", password='****" + '\'' +
", authorities=" + authorities +
", AuthToken='" + authToken + '\'' +
'}';
}
}
这是我的 WebSecurityConfig:
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(customAuthenticationProvider)
.ldapAuthentication()
.userSearchFilter("(&(mail={0})(memberOf=CN=aa,OU=Security Group,OU=aa,DC=aa,DC=com))")
.contextSource()
.url("ldap://www.domain.com:3268/dc=v,dc=com")
.managerDn("aaa")
.managerPassword("aaa");
}
存储库Class:
@Repository
public class UserAuthRepository {
@Autowired
private InterServiceConnector serviceConnector;
@Autowired
private httpsServiceConnector httpsServiceConnector;
private static final org.slf4j.Logger LOG
= LoggerFactory.getLogger(CustomAuthenticationProvider.class);
@Value("${dmzAddress}")
private String host;
public CustomUser authenticateUser(String userName, String password) {
CustomUser customUser = null;
try {
customUser = null;
LOG.info("UserAuthRepository::authenticateUser:: userName" + userName);
// LOG.info("UserAuthRepository::authenticateUser:: password ********");
Request request = new Request();
request.setUsername(userName);
request.setPassword(password);
Gson gson = new GsonBuilder().create();
String jsonInput = gson.toJson(request);
// LOG.info("UserAuthRepository::authenticateUser:: Authentication Token :: " + request.getAuthToken());
String user = null;
if (host.contains("http://")){
user = serviceConnector.serviceCall(jsonInput, "portalLogin", "post", request.getAuthToken());
}
else{
user = httpsServiceConnector.serviceCall(jsonInput, "portalLogin", "post");
}
// String user = serviceConnector.serviceCall(jsonInput, "portalLogin", "post", request.getAuthToken());
// String user = httpsServiceConnector.serviceCall(jsonInput, "portalLogin", "post");
// LOG.info("UserAuthRepository::authenticateUser:: user---->>> " + user);
customUser = gson.fromJson(user, CustomUser.class);
LOG.info("UserAuthRepository:: Custom User:: {}", customUser);
} catch (JsonSyntaxException e) {
LOG.error("UserAuthRepository :: authenticateUser :: Parse Exception", e);
}
return customUser;
}
}
首先,您的 CustomUser 应该实现 LdapUserDetails
而不是 UserDetails
您还需要 subclass LdapUserDetailsMapper
因为 Spring 将调用 mapUserFromContext
并且您可以在此处从数据库中获取所需的任何数据并创建一个CustomUser 的实例。
@Component
public class CustomLdapUserDetailsMapper extends LdapUserDetailsMapper {
@Autowired
private IUserRepository userRepository;
@Autowired
private IUserRoleRepository userRoleRepository;
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<? extends GrantedAuthority> authorities) {
User user = userRepository.findOneByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("Username not found");
}
UserDetails userDetails = super.mapUserFromContext(ctx, username, getAuthorities(user));
//add a constructor for your CustomUser
return new CustomUser(user.getEmail(), user.getFullName(), (LdapUserDetails) userDetails);
}
}
private Set<GrantedAuthority> getAuthorities(User user) {
Set<GrantedAuthority> authorities = new HashSet<>();
//populate authorities/user roles from User (db entity) and UserRole entities
for (UserRole userRole : userRoleRepository.findAllByUserId(user.getId())) {
authorities.add(new SimpleGrantedAuthority(userRole.getRole.getName()));
}
return authorities;
}
}
最后,告诉您的身份验证提供商使用此 ldap 映射器 class(将其放入您的网络安全代码中)
@Autowired
private CustomLdapUserDetailsMapper customLdapUserDetailsMapper;
....
customAuthenticationProvider.setUserDetailsContextMapper(customLdapUserDetailsMapper);
更新:CustomUser 代码可能看起来像这样
public class CustomUser implements LdapUserDetails{
private String email;
private String fullName;
private String username;
private LdapUserDetails ldapUserDetails;
public CustomUser(String email, String fullName, LdapUserDetails ldapUserDetails) {
super();
this.email = email;
this.fullName = fullName;
this.ldapUserDetails = ldapUserDetails;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return ldapUserDetails.getAuthorities();
}
@Override
public String getPassword() {
return ldapUserDetails.getPassword();
}
@Override
public String getUsername() {
return ldapUserDetails.getUsername();
}
//add all the other overrides and getter/setter methods
}
存储库 classes 可能类似于
public interface IUserRepository extends JpaRepository<User, Integer> {
public User findOneByUsername(String username);
public User findOneById(Integer id);
public User findOneByEmail(String email);
}
public interface IUserRoleRepository extends JpaRepository<UserRole, Integer> {
UserRole findOneByRoleName(String rolename);//role name like admin, user, mod etc
UserRole findOneById(Integer id);//role id
}
@dsp_user给出了很好的解决方案。
现在,根据您上面的代码,我假设您正在使用存储库 Class 中的一个函数,该函数将用户名和密码作为参数。
做类似的另一个功能,只接受用户名作为参数。在您的 CustomLdapUserDetailsMapper Class.
中调用该函数试试这个代码:
@Component
public class CustomLdapUserDetailsMapper extends LdapUserDetailsMapper {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
CustomUser user = userRepository.authenticationMethod(username);
if (user == null) {
throw new UsernameNotFoundException("User is not found!");
}
return user;
}
}
我希望这能解决问题。