AuthenticationProvider

AuthenticationProvider

为了获得我的帐户,我需要登录一个外部spring应用程序。为什么需要它并不重要,但是为了对API进行/ login调用,我需要在UserDetailsS​​erviceMethod中获取密码。这是我的安全设置:

//https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
    private UserDetailsService userDetailsService;
    private BCryptPasswordEncoder bCryptPasswordEncoder;

//Constructor gets authLogic for external authentication
@Autowired
public WebSecurity(@Qualifier("authLogic") UserDetailsService userDetailsService){
    this.userDetailsService = userDetailsService;
    this.bCryptPasswordEncoder = new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable()
            .authorizeRequests()
            .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilter(new JwtAuthenticationFilter(authenticationManager()))
            .addFilter(new JwtAuthorizationFilter(authenticationManager()))
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    final CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList(BANK_API, INVENTORY_API, MARKET_API)); //TODO: is dit correct??
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH"));
    configuration.setAllowCredentials(true);
    configuration.setAllowedHeaders(Arrays.asList("*"));
    configuration.setExposedHeaders(Arrays.asList("X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));

    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}
}


我的UserDetailsS​​erviceMethod实现:

@Service
public class AuthLogic implements UserDetailsService {
    private HttpServletRequest request;
    private IAccountRepository accountRepository;
    private RestCallLogic restCall;

    @Autowired
    public AuthLogic(HttpServletRequest request, IAccountRepository accountRepository, RestCallLogic restCall){
        this.request = request;
        this.accountRepository = accountRepository;
        this.restCall = restCall;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //get password
        //make restcall to external login
    }
}


有没有一种方法可以在使用Spring Security实现时获取密码。因为我可以轻松地创建自己的类并从那里进行登录,但是最好使用Spring安全性。登录名还会返回一个令牌,我可以将其重新分配给用户。也许我只是在想...

为了进行API调用,我需要编写一个自定义AuthenticationProvider:

@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        UserDetails principal = new User(username, password, new ArrayList<>());

        return new UsernamePasswordAuthenticationToken(principal, password, new ArrayList<>());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

最佳答案

在后台,Spring Security在过滤器中解析用户的凭证(例如BasicAuthenticationFilterUsernamePasswordAuthenticationFilter等-过滤器检索用户凭证),如果这样的过滤器成功检索了用户的凭证,它将把这些凭证传递给AuthenticationProvider来验证凭证和创建用户的详细信息(read more about AuthenticationProvider)。 AuthenticationProvider可以通过多种方式验证凭据。

AuthenticationProvider的一种实现是DaoAuthenticationProvider,它尝试通过UserDetailsService中的用户名查找用户,如果找到,则从UserDetails中为用户获取UserDetailsService,然后检查用户提供的密码是否满足要求UserDetails中的密码。

在您的情况下,您需要在UserDetailsService中而不是在AuthenticationProvider中提出这样的请求,因为它负责这种情况。

我的建议是从Spring安全性扩展AbstractUserDetailsAuthenticationProvider类,并以抽象方法protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;实现您的功能。

例如:

@Configuration
public class WebSecurityConf43547 extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new AbstractUserDetailsAuthenticationProvider() {
            @Override
            protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
                //from docs: "[...]Generally a subclass will at least compare the
                //Authentication.getCredentials() with a UserDetails.getPassword() [...]"
            }

            @Override
            protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
                usernamePasswordAuthenticationToken.getCredentials();
                //your api here
            }
        });
    }
}


更好的例子:看看DaoAuthenticationProvider如何在Spring安全性中扩展AbstractUserDetailsAuthenticationProvider

10-06 05:28