如何在Sping Boot 中实现基于Spring Security的登录服务测试?

mftmpeh8  于 2023-03-23  发布在  Spring
关注(0)|答案(2)|浏览(140)

我在Sping Boot 中基于Spring Security实现登录服务测试时遇到问题。我尝试在AuthService中实现登录方法,然后编写其服务方法,但我遇到了问题。
下面是问题显示

java.lang.NullPointerException: Cannot invoke "org.springframework.security.core.Authentication.getPrincipal()" because "auth" is null

我该怎么修呢?
下面是JwtUserDetails类

@RequiredArgsConstructor
public class JwtUserDetails implements UserDetails {

    private final User user;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        UserRole roles = user.getUserRole();

        List<SimpleGrantedAuthority> authories = new ArrayList<>();
        authories.add(new SimpleGrantedAuthority(roles.name()));

        return authories;
    }

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

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

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

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

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

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

    public long getId(){
        return user.getId();
    }

    public String getEmail(){
        return user.getEmail();
    }
}

下面是AuthService

@Service
@RequiredArgsConstructor
public class AuthService{

    private final AuthenticationManager authenticationManager;

    private final JwtTokenProvider jwtTokenProvider;

    private final PasswordEncoder passwordEncoder;
   
    private final RefreshTokenService refreshTokenService;

    @Override
    @Transactional
    public AuthResponse login(AdminLoginRequest loginRequest) {

        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
        Authentication auth = authenticationManager.authenticate(authToken);
        SecurityContextHolder.getContext().setAuthentication(auth);
        JwtUserDetails userDetails = (JwtUserDetails) auth.getPrincipal();
        String accessToken = jwtTokenProvider.generateJwtToken(auth);

        List<String> roles = userDetails.getAuthorities().stream().map(item -> item.getAuthority())
                .collect(Collectors.toList());

        RefreshToken refreshToken = refreshTokenService.createRefreshToken(userDetails.getId());

        Date expiryDate = new Date(new Date().getTime() + EXPIRES_IN);

        return AuthResponse.builder()
                .username(userDetails.getUsername())
                .accessToken("Bearer " + accessToken)
                .roles(roles)
                .refreshToken(refreshToken.getToken())
                .message("success")
                .expireDate(expiryDate.getTime())
                .build();
    }

下面是AuthServiceTest

@ExtendWith(MockitoExtension.class)
class AuthServiceTest{

    @Mock
    private UserRepository userRepository;

    @Mock
    private OrganizationRepository organizationRepository;

    @InjectMocks
    private AuthServiceImpl authService;

    @Mock
    private PasswordEncoder passwordEncoder;

    @Mock
    private UserMapper userMapper;

    @Mock
    private RefreshTokenService refreshTokenService;

    @Mock
    private JwtTokenProvider jwtTokenProvider;

    @Mock
    private AuthenticationManager authenticationManager;

@Test
    void shouldLogin() {

        // Given
        AdminLoginRequest loginRequest = getLoginRequest();

        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
        Authentication auth = authenticationManager.authenticate(authToken);
        SecurityContextHolder.getContext().setAuthentication(auth);
        JwtUserDetails userDetails = (JwtUserDetails) auth.getPrincipal();

        AuthResponse authResponse = AuthResponse.builder()
                .expireDate(new Date().getTime() + 120000)
                .refreshToken("refreshToken")
                .message("success")
                .accessToken("Bearer access-token")
                .roles(List.of("ADMIN","SUPER_ADMIN"))
                .username("adminUsername")
                .build();

        RefreshToken refreshToken = RefreshToken.builder()
                .token(authResponse.getAccessToken())
                .build();

        // when
        when(authenticationManager.authenticate(any())).thenReturn(authToken);
        when(jwtTokenProvider.generateJwtToken(any())).thenReturn(authResponse.getAccessToken());
        when(refreshTokenService.createRefreshToken(eq(userDetails.getId()))).thenReturn(refreshToken);

        AuthResponse authResponseActual = authService.login(loginRequest);

        // then
        assertThat(authResponse).isNotNull();
        assertEquals(authResponseActual.getAccessToken(), authResponse.getAccessToken());
        assertEquals(authResponseActual.getUsername(), authResponse.getUsername());
        assertEquals(authResponseActual.getRefreshToken(), authResponse.getRefreshToken());
        assertEquals(authResponseActual.getRefreshToken(), authResponse.getRefreshToken());
        assertEquals(authResponseActual.getMessage(), authResponse.getMessage());

    }

下面是getLoginRequest

public AdminLoginRequest getLoginRequest() {
        return AdminLoginRequest.builder()
                .username("adminUsername")
                .password("adminPassword")
                .build();
    }

订正
下面是测试方法

@Test
    void shouldLogin() {

        // Given
        AdminLoginRequest loginRequest = new UserBuilder().getLoginRequest();

        User user = User.builder()
                .username(loginRequest.getUsername())
                .password(loginRequest.getPassword())
                .userRole(UserRole.ROLE_ADMIN)
                .build();

        user.setId(1L);

        UsernamePasswordAuthenticationToken authToken =
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());

        SecurityContextHolder.getContext().setAuthentication(auth);

        AuthResponse authResponse = AuthResponse.builder()
                .expireDate(new Date().getTime() + 120000)
                .refreshToken("refreshToken")
                .message("success")
                .accessToken("Bearer access-token")
                .roles(List.of("ADMIN","SUPER_ADMIN"))
                .username("adminUsername")
                .build();

        RefreshToken refreshToken = RefreshToken.builder()
                .token(authResponse.getAccessToken())
                .build();

        // when
        when(authenticationManager.authenticate(eq(authToken))).thenReturn(authToken);
        when(auth.getPrincipal()).thenReturn(jwtUserDetails);
        when(jwtTokenProvider.generateJwtToken(eq(auth))).thenReturn(authResponse.getAccessToken());
        when(refreshTokenService.createRefreshToken(eq(jwtUserDetails.getId()))).thenReturn(refreshToken);

        AuthResponse authResponseActual = authService.login(loginRequest);

        // then
        assertThat(authResponse).isNotNull();
        assertEquals(authResponseActual.getAccessToken(), authResponse.getAccessToken());
        assertEquals(authResponseActual.getUsername(), authResponse.getUsername());
        assertEquals(authResponseActual.getRefreshToken(), authResponse.getRefreshToken());
        assertEquals(authResponseActual.getRefreshToken(), authResponse.getRefreshToken());
        assertEquals(authResponseActual.getMessage(), authResponse.getMessage());

    }

下面是问题显示

java.lang.ClassCastException: class java.lang.String cannot be cast to class com.ays.backend.user.security.JwtUserDetails (java.lang.String is in module java.base of loader 'bootstrap'; com.ays.backend.user.security.JwtUserDetails is in unnamed module of loader 'app')
dsekswqp

dsekswqp1#

JwtUserDetails jwtUserDetails:

@Mock
private Authentication auth

@Mock
private JwtUserDetails jwtUserDetails

and in test do

when(auth.getPrincipal()).thenReturn(jwtUserDetails)

不要忘记在测试中删除两行代码

Authentication auth = authenticationManager.authenticate(authToken);
JwtUserDetails userDetails = (JwtUserDetails) auth.getPrincipal();
jhdbpxl9

jhdbpxl92#

下面是答案

@Test
    void shouldLogin() {

        // Given
        AdminLoginRequest loginRequest = new UserBuilder().getLoginRequest();

        User user = User.builder()
                .username(loginRequest.getUsername())
                .password(loginRequest.getPassword())
                .userRole(UserRole.ROLE_ADMIN)
                .build();

        user.setId(1L);

        UsernamePasswordAuthenticationToken authToken =
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());

        JwtUserDetails jwtUserDetails = new JwtUserDetails(user);

        Authentication auth = new UsernamePasswordAuthenticationToken(jwtUserDetails, null);

        SecurityContextHolder.getContext().setAuthentication(auth);

        JwtUserDetails userDetails = (JwtUserDetails) auth.getPrincipal();

        AuthResponse authResponse = AuthResponse.builder()
                .expireDate(new Date().getTime() + 120000)
                .refreshToken("refreshToken")
                .message("success")
                .accessToken("access-token")
                .roles(List.of("ADMIN","SUPER_ADMIN"))
                .username("adminUsername")
                .build();

        RefreshToken refreshToken = RefreshToken.builder()
                .token(authResponse.getRefreshToken())
                .build();

        // when
        when(authenticationManager.authenticate(eq(authToken)))
                .thenReturn(auth);
        when(jwtTokenProvider.generateJwtToken(eq(auth))).thenReturn(authResponse.getAccessToken());
        when(refreshTokenService.createRefreshToken(eq(userDetails.getId()))).thenReturn(refreshToken);

        AuthResponse authResponseActual = authService.login(loginRequest);

        // then
        assertThat(authResponse).isNotNull();
        assertEquals(authResponseActual.getAccessToken().substring(7), authResponse.getAccessToken());
        assertEquals(authResponseActual.getUsername(), authResponse.getUsername());
        assertEquals(authResponseActual.getRefreshToken(), authResponse.getRefreshToken());
        assertEquals(authResponseActual.getMessage(), authResponse.getMessage());

    }

相关问题