Spring Security возвращает 401 даже за действительный JWT - PullRequest
0 голосов
/ 25 октября 2019

Я настроил Spring Security и могу успешно сгенерировать JWT, однако, когда я использую сгенерированный JWT для доступа к защищенному ресурсу, я получаю ошибку 401. Я использую Почтальон для доступа к конечным точкам REST.

Вот код Spring Security, который я настроил. Любые указатели на то, что не так с этой настройкой?

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {  
    @Autowired
    private ApplicationUserDetailsService userDetailsService;

    @Autowired
    private ClientDetailsService clientDetailsService;  

    @Override
    @Order(Ordered.HIGHEST_PRECEDENCE)
    protected void configure(HttpSecurity http) throws Exception {
        http
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/oauth/token").permitAll()
        .antMatchers("/rm/**").permitAll()
        .anyRequest().authenticated()
        .and()
        .httpBasic()
            .realmName(OAuthConstants.REALM);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
        .parentAuthenticationManager(authenticationManagerBean())
        .userDetailsService(userDetailsService)
        .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(getJWTAccessTokenConverter());
    }

    @Bean
    protected JwtAccessTokenConverter getJWTAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(OAuthConstants.JWT_TOKEN_SIG_KEY);
        return converter;
    }   

    @Bean
    @Autowired
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Bean
    @Autowired
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore);
        return store;
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private UserApprovalHandler userApprovalHandler;

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    private ApplicationUserDetailsService userDetailsService;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
        .tokenStore(tokenStore)
        .tokenEnhancer(jwtAccessTokenConverter)
        .userApprovalHandler(userApprovalHandler)
        .authenticationManager(authenticationManager)
        .userDetailsService(userDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.realm(OAuthConstants.REALM);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
        .withClient(OAuthConstants.CLIENT_ID)
        .secret(new BCryptPasswordEncoder().encode(OAuthConstants.CLIENT_SECRET))
        .authorizedGrantTypes("password", "refresh_token")
        .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
        .scopes("read", "write", "trust")
        .accessTokenValiditySeconds(OAuthConstants.ONE_DAY)
        .refreshTokenValiditySeconds(OAuthConstants.THIRTY_DAYS);
    }
}

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        //URL patterns to enable OAuth2 security
        http
        .anonymous().disable()
        .requestMatchers()
            .antMatchers("/md/**", "/a/**", "/s/**", "/b/**")
        .and()
        .authorizeRequests()
            .antMatchers("/md/**", "/a/**", "/s/**", "/b/**").hasRole("O")
            .antMatchers("/md/**", "/a/**", "/s/**", "/b/**").hasRole("A")
            .antMatchers("/md/**", "/a/**", "/s/**", "/b/**").hasRole("S")
        .and()
        .exceptionHandling()
            .accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }   
}

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}

@Service
public class ApplicationUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        username = username.toLowerCase();
        Credentials c = CHandlerAdapter.getCredentials(username);
        if(username.startsWith("s.")) {         
            try {           
                return new ApplicationUserDetails(username, c.getPassword(), ApplicationUserDetails.S);
            }
            catch(Exception e) {
                throw new UsernameNotFoundException(e.getMessage());
            }
        }
        else if(username.startsWith("a.")) {                
            try {
                return new ApplicationUserDetails(username, c.getPassword(), ApplicationUserDetails.A);
            }
            catch(Exception e) {
                throw new UsernameNotFoundException(e.getMessage());
            }
        }
        else if(username.equals("o")) {
            try {
                return new ApplicationUserDetails(username, new BCryptPasswordEncoder().encode("testp"), ApplicationUserDetails.O);
            }
            catch(Exception e) {
                throw new UsernameNotFoundException(e.getMessage());
            }
        }
        else {
            logger.error("Invalid username: " + username);
            throw new UsernameNotFoundException("Invalid username");
        }
    }
}

public class ApplicationUserDetails implements UserDetails {
    private static final long serialVersionUID = 1L; 

    private String username; 
    private String password; 
    private Collection<? extends GrantedAuthority> authorities;

    public static final String S = "S";
    public static final String A = "A";
    public static final String O = "O";

    public ApplicationUserDetails() {
    }

    public ApplicationUserDetails(String username, String password, String userType) {
        this.username = username;
        this.password = password;

        if(userType.contentEquals(S))
            this.authorities = Arrays.asList(new SimpleGrantedAuthority("ROLE_S"));
        else if(userType.contentEquals(A))
            this.authorities = Arrays.asList(new SimpleGrantedAuthority("ROLE_A"));
        else if(userType.contentEquals(O))
            this.authorities = Arrays.asList(new SimpleGrantedAuthority("ROLE_O"));
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

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

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

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

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