自定义用户详细信息和JwtFilter请求和服务,用户主体位于加载器应用程序org.springframework.security.core.userdetails的未命名模块中,用户

o0lyfsai  于 2022-12-26  发布在  Spring
关注(0)|答案(1)|浏览(130)

我正在尝试登录用户,但遇到以下异常,

ava.lang.ClassCastException: class org.springframework.security.core.userdetails.User cannot be cast to class com.gaurav.studentmanagement.customUserdetailsAndJwtFilterRequestsAndServices.UserPrincipal (org.springframework.security.core.userdetails.User and com.gaurav.studentmanagement.customUserdetailsAndJwtFilterRequestsAndServices.UserPrincipal are in unnamed module of loader 'app')

我的UserPrincipal类是:

package com.gaurav.studentmanagement.customUserdetailsAndJwtFilterRequestsAndServices;

import com.gaurav.studentmanagement.entity.User;
import com.gaurav.studentmanagement.repo.RolesRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


public class UserPrincipal implements UserDetails {


private final User user;

private List<String> grantedAuthorities;

public UserPrincipal(User user){
    this.user=user;
}

@Override
public Collection< ? extends GrantedAuthority > getAuthorities() {
    List<GrantedAuthority> authorities = new ArrayList<>();
    getGrantedAuthorities().forEach(p -> {
        GrantedAuthority authority = new SimpleGrantedAuthority(p);
        authorities.add(authority);
    });

    // Extract list of roles (ROLE_name)
    getGrantedAuthorities().forEach(r -> {
        GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + r);
        authorities.add(authority);
    });

    return authorities;
}

@Override
public String getPassword() {
    return this.user.getPassword();
}

public User getUser(){
    return user;
}

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

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

public List<String> getGrantedAuthorities() {
    return grantedAuthorities;
}

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

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

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

}
我正在使用以下方法获取登录用户:

@Override
public User getLoggedInUser() {
    UserPrincipal userPrincipal = (UserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    User user=userPrincipal.getUser();
    if(user==null){
        throw new CustomException("Not authorized");
    }
    return user;

}

每当调试器指向:

UserPrincipal userPrincipal = (UserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

抛出上面的异常,可能是什么问题,我试图从getLoggedInUser返回User,但是不知道哪里出错了,我想我返回了正确的User,得到了本金,但是找不到哪里出错了。
自定义用户详细信息服务类:

package com.gaurav.studentmanagement.customUserdetailsAndJwtFilterRequestsAndServices;

import com.gaurav.studentmanagement.entity.Roles;
import com.gaurav.studentmanagement.entity.User;
import com.gaurav.studentmanagement.repo.RolesRepo;
import com.gaurav.studentmanagement.repo.UserRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
public class CustomUserDetails implements UserDetailsService {

    @Autowired
    UserRepo userRepo;
    @Autowired
    RolesRepo rolesRepo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional< User > user = userRepo.fetchByEmail(username);

        if (user.isPresent()) {
            List< Roles > roles = rolesRepo.findByUserId(user.get().getuId());
            System.out.println(roles + " are the roles");
            List< SimpleGrantedAuthority > authorities = new ArrayList<>();
            for (Roles roles1 : roles) {
                System.out.println(roles1.getRoleName()+" are the roles");
                authorities.add(new SimpleGrantedAuthority(roles1.getRoleName()));
            }
            return new org.springframework.security.core.userdetails.User(user.get().getEmail(), user.get().getPassword(), authorities);
        }
        else {
            throw new UsernameNotFoundException("User "+ username+" does not exist");
        }
    }
}
vvppvyoh

vvppvyoh1#

你的UserPrincipalorg.springframework.security.core.userdetails.User都实现了UserDetails接口,但是它们不互相扩展,这些类是兄弟类,它们中的任何一个都可以用来代替它们的父类型UserDetails,但是你不能把一个强制转换成另一个。
由于最终您希望使用自定义实现UserPrincipal来表示UserDetails,因此问题的解决方案是停止使用Spring SecurityTM提供的User类,并基于您从loadUserByUsername()中的数据库检索的自定义User类的示例来构造UserPrincipal
以下是它的实现方式:

@Service
@AllArgsConstructor // or define all-args constructor manually (don't use field injection)
class CustomUserDetails implements UserDetailsService {
    private UserRepo userRepo;
    private RolesRepo rolesRepo;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        
        return userRepo.fetchByEmail(username)
            .map(user -> new UserPrincipal(
                user,
                rolesRepo.findByUserId(user.get().getuId()).stream()
                    .map(role -> new SimpleGrantedAuthority(role.getRoleName()))
                    .toList() // for Java 16+ collect(Collectors.toList())
            ))
            .orElseThrow(() -> new UsernameNotFoundException("User " + username + " does not exist"));
    }
}

注:

  • 建议使用 * constructor injection * 而不是 * field injection *,因此我从字段中删除了@Autowired,并添加了Lombok的注解@AllArgsConstructor(或者,如果您在项目中没有使用Lombok,则可以要求IDE为您生成构造函数,请注意,除非您有多个构造函数,否则不需要使用@Autowired进行注解)。
  • 您还需要在UserPrincipal中定义all-args构造函数,因为它在上面显示的loadUserByUsername()实现中使用(或者您可以使用@Builder构建器注解):
@AllArgsConstructor // or define all-args constructor manually
class UserPrincipal implements UserDetails

相关问题