java - How do I get User id from unprotected URLs? - Stack Overflow

admin2025-04-18  3

I have AuthenticatedUser class which extends org.springframework.security.core.userdetails.User. It is constructed from JWT.

Every request from the browser has JWT attached to the request. The pages are either protected or public. If a page is protected my @AuthenticationPrincipal AuthenticatedUser principal is populated but if the if the page is not protected my @AuthenticationPrincipal AuthenticatedUser principal is not populated. And the problem arises here. Now I have a case where I want to get the @AuthenticationPrincipal AuthenticatedUser principal even when the page is not protected. But now in unprotected pages my @AuthenticationPrincipal AuthenticatedUser principal appears to be null, even though I send JWT.

@Configuration
@EnableWebSecurity
public class ResourceServerConfig {

    private final List<String> protectedPaths = List.of(
            "/secret/*/**",
            "/private"
    );
    // here if I add the public into the list principal is populated but the anon users cannot access the public link. If I don't add the public link then principal appears to be null.

    @Bean
    @Order(2)
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .securityMatchers(customizer -> customizer.requestMatchers(protectedPaths.toArray(new String[0])))
                .csrf().disable()
                .authorizeHttpRequests(requests -> requests.anyRequest().authenticated())
                .oauth2ResourceServer()
                .jwt(customizer -> customizer.jwtAuthenticationConverter(new UserAuthenticationTokenConverter()));
        return http.build();
    }
}

And my controller is as following:

@GetMapping(path = "/public/{id}")
public ListingDetailedView
findById(@PathVariable String id, @AuthenticationPrincipal AuthenticatedUser principal) {
    // here principal is null
    return listingService.findBySearchId(id, principal);
}

How I can populate the principal on not protected pages?

Edit: My other security filter is as follows which handles only one end-point:

@Configuration
@RequiredArgsConstructor
public class PartnerResourceServerConfig {

    private final PartnerUserDetailsService userDetailsService;
    private final AuthenticationFailureHandler failureHandler;

    @Bean
    @Order(1)
    public SecurityFilterChain partnerSecurityFilterChain(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
        authManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
        var authenticationManager = authManagerBuilder.build();

        http.securityMatcher("/hidden/**")
                .authorizeHttpRequests(customizer -> customizer.anyRequest().authenticated())
                .authenticationManager(authenticationManager)
                .addFilterBefore(partnerApiKeyAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class)
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(sessionManagementCustomizer -> sessionManagementCustomizer
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        return http.build();
    }

    PartnerApiKeyAuthenticationFilter partnerApiKeyAuthenticationFilter(AuthenticationManager authenticationManager) {
        var filter = new PartnerApiKeyAuthenticationFilter("/hidden/**");
        filter.setAuthenticationFailureHandler(failureHandler);
        filter.setAuthenticationManager(authenticationManager);
        return filter;
    }

}

Additional classes:

@NoArgsConstructor
public class UserAuthenticationTokenConverter implements Converter<Jwt, AuthenticationToken> {

    @Override
    public AuthenticationToken convert(Jwt source) {
        var authenticatedUser = AuthenticatedUser.from(source);
        return new AuthenticationToken(source, authenticatedUser);
    }
}

AuthenticationToken:

public class AuthenticationToken extends AbstractAuthenticationToken {

    private final Jwt jwt;
    private final AuthenticatedUser authenticatedUser;

    public AuthenticationToken(Jwt jwt, AuthenticatedUser authenticatedUser) {
        super(List.of());
        this.jwt = jwt;
        this.authenticatedUser = authenticatedUser;
    }

    @Override
    public Object getCredentials() {
        return this.jwt;
    }

    @Override
    public Object getPrincipal() {
        return authenticatedUser;
    }

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

Simplified AuthenticatedUser:

@Getter
public class AuthenticatedUser extends User {

    private final String id;
    private final UserRole role;
    private final String email;

    private final boolean isPhoneVerified;

    private AuthenticatedUser(String id, UserRole role, String email, String token,
                              boolean isPhoneVerified) {
        super(id, token, true, true, true, true, List.of());
        this.id = id;
        this.role = role;
        this.email = email;
        this.isPhoneVerified = isPhoneVerified;
    }

    @SuppressWarnings("unchecked")
    public static AuthenticatedUser from(Jwt jwt) {
        var id = jwt.getSubject();
        var roleClaim = jwt.getClaimAsString("type");
        var userRole = UserRole.forValue(roleClaim);
        var userEmail = jwt.getClaimAsString("email");
        var isPhoneVerifiedString = jwt.getClaimAsBoolean("phone_number_verified");
        var isPhoneVerified = isPhoneVerifiedString != null ? isPhoneVerifiedString : false;
        return new AuthenticatedUser(id, userRole, userEmail, jwt.getTokenValue(), isPhoneVerified);
    }
}
转载请注明原文地址:http://www.anycun.com/QandA/1744911769a89371.html