2014-12-16 2 views
27

Я пытаюсь настроить Spring Security с помощью конфигурации Java в базовом веб-приложении для аутентификации с помощью внешней веб-службы с использованием зашифрованного токена, предоставленного в параметре запроса URL-адреса.Специальный фильтр проверки подлинности Spring Security с использованием Java Config

Я бы хотел (я думаю) иметь фильтр безопасности, который перехватывает запросы из портала входа (все они идут/аутентифицируются), фильтр будет использовать AuthenticationProvider для обработки логики бизнес-процесса аутентификации.

Login Portal -> Redirect '\ authenticate' (+ Token) -> Authenticate Token back to Login Portal (WS) -> Если успех получает роли и настраивает пользователя.

Я создал фильтр ..

@Component 
public final class OEWebTokenFilter extends GenericFilterBean { 
    @Override 
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { 
     if (request instanceof HttpServletRequest) { 
      OEToken token = extractToken(request); 
      // dump token into security context (for authentication-provider to pick up) 
      SecurityContextHolder.getContext().setAuthentication(token); 
     } 
    } 
    chain.doFilter(request, response); 
} 

AuthenticationProvider ...

@Component 
public final class OEWebTokenAuthenticationProvider implements AuthenticationProvider { 
    @Autowired 
    private WebTokenService webTokenService; 

    @Override 
    public boolean supports(final Class<?> authentication) { 
     return OEWebToken.class.isAssignableFrom(authentication); 
    } 

    @Override 
    public Authentication authenticate(final Authentication authentication) { 
     if (!(authentication instanceof OEWebToken)) { 
      throw new AuthenticationServiceException("expecting a OEWebToken, got " + authentication); 
     } 

     try { 
      // validate token locally 
      OEWebToken token = (OEWebToken) authentication; 
      checkAccessToken(token); 

      // validate token remotely 
      webTokenService.validateToken(token); 

      // obtain user info from the token 
      User userFromToken = webTokenService.obtainUserInfo(token); 

      // obtain the user from the db 
      User userFromDB = userDao.findByUserName(userFromToken.getUsername()); 

      // validate the user status 
      checkUserStatus(userFromDB); 

      // update ncss db with values from OE 
      updateUserInDb(userFromToken, userFromDB); 

      // determine access rights 
      List<GrantedAuthority> roles = determineRoles(userFromDB); 

      // put account into security context (for controllers to use) 
      return new AuthenticatedAccount(userFromDB, roles); 
     } catch (AuthenticationException e) { 
      throw e; 
     } catch (Exception e) { 
      // stop non-AuthenticationExceptions. otherwise full stacktraces returned to the requester 
      throw new AuthenticationServiceException("Internal error occurred"); 
     } 
    } 

И моя Spring Security Config

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    OESettings oeSettings; 

    @Bean(name="oeAuthenticationService") 
    public AuthenticationService oeAuthenticationService() throws AuthenticationServiceException { 
     return new AuthenticationServiceImpl(new OEAuthenticationServiceImpl(), oeSettings.getAuthenticateUrl(), oeSettings.getApplicationKey()); 
    } 

    @Autowired 
    private OEWebTokenFilter tokenFilter; 

    @Autowired 
    private OEWebTokenAuthenticationProvider tokenAuthenticationProvider; 

    @Autowired 
    private OEWebTokenEntryPoint tokenEntryPoint; 

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

    @Override 
    public void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.authenticationProvider(tokenAuthenticationProvider); 
    } 

    @Bean 
    public FilterRegistrationBean filterRegistrationBean() { 
     FilterRegistrationBean registrationBean = new FilterRegistrationBean();  
     registrationBean.setFilter(tokenFilter);  
     registrationBean.setEnabled(false); 
     return registrationBean; 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.csrf().disable() 
      .authorizeRequests() 
      .antMatchers("/authenticate**").permitAll() 
      .antMatchers("/resources/**").hasAuthority("ROLE_USER") 
      .antMatchers("/home**").hasAuthority("ROLE_USER") 
      .antMatchers("/personSearch**").hasAuthority("ROLE_ADMIN") 
      // Spring Boot actuator endpoints 
      .antMatchers("/autoconfig**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/beans**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/configprops**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/dump**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/env**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/health**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/info**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/mappings**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/metrics**").hasAuthority("ROLE_ADMIN") 
      .antMatchers("/trace**").hasAuthority("ROLE_ADMIN") 
      .and() 
       .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class) 
       .authenticationProvider(tokenAuthenticationProvider) 
       .antMatcher("/authenticate/**") 
       .exceptionHandling().authenticationEntryPoint(tokenEntryPoint) 
      .and() 
       .logout().logoutSuccessUrl(oeSettings.getUrl()); 
    } 
} 

Моя проблема заключается в конфигурации фильтра в моем классе SpringConfig. Я хочу, чтобы фильтр только вступал в силу, когда запрос предназначен для/аутентификации URL, я добавил .antMatcher ("/ authenticate/**") в конфигурацию фильтра.

.and() 
       .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class) 
       .authenticationProvider(tokenAuthenticationProvider) 
       .antMatcher("/authenticate/**") 
       .exceptionHandling().authenticationEntryPoint(tokenEntryPoint) 

Когда у меня эта линия во всех других URL-адресах больше не защищено, я могу вручную перейти к/дома без аутентификации, удалить строку и/дом подлинность.

Должен ли я объявлять фильтр, применимый только к определенному URL-адресу?

Как я могу реализовать это, сохраняя безопасность других URL-адресов?

+0

Спасибо для кетсиона. :) Помогает! – raj

ответ

12

Я решить мою проблему, выполняя проверку состояния аутентификации в фильтре до того involking поставщика проверки подлинности ....

Config

.and() 
    .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class) 
    .authenticationProvider(tokenAuthenticationProvider) 
    .exceptionHandling().authenticationEntryPoint(tokenEntryPoint) 

Фильтр

@Override 
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) 
     throws IOException, ServletException { 

    logger.debug(this + "received authentication request from " + request.getRemoteHost() + " to " + request.getLocalName()); 

    if (request instanceof HttpServletRequest) { 
     if (isAuthenticationRequired()) { 
      // extract token from header 
      OEWebToken token = extractToken(request); 

      // dump token into security context (for authentication-provider to pick up) 
      SecurityContextHolder.getContext().setAuthentication(token); 
     } else { 
      logger.debug("session already contained valid Authentication - not checking again"); 
     } 
    } 

    chain.doFilter(request, response); 
} 

    private boolean isAuthenticationRequired() { 
    // apparently filters have to check this themselves. So make sure they have a proper AuthenticatedAccount in their session. 
    Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); 
    if ((existingAuth == null) || !existingAuth.isAuthenticated()) { 
     return true; 
    } 

    if (!(existingAuth instanceof AuthenticatedAccount)) { 
     return true; 
    } 

    // current session already authenticated 
    return false; 
} 
+4

Можете ли вы опубликовать код этих классов: 'OEWebToken',' AuthenticatedAccount' и 'extractToken (request)' метод реализации? Я бы очень помог мне с моим отдыхом. Заранее спасибо. – masterdany88

Смежные вопросы