2013-06-15 7 views
5

У меня есть сервер с API. Сервер защищен Spring Security.Проверка подлинности Spring Security через токен

Я хочу, чтобы иметь доступ к API из внешних приложений с использованием маркеров в запросе параметров

Во-первых, пользователь будет идти на службу, которая дает ему маркер, а затем получить доступ к API с этим маркером.

Но я хочу сохранить предыдущий доступ к API через стандартные решения Spring Security.

Итак, не могли бы вы помочь мне, как я могу это реализовать?

+0

Проверьте поддержку OAuth. –

ответ

7

Вы должны реализовать пользовательский AuthenticationFilter как этот

public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 

    private static final String SECURITY_TOKEN_KEY = "token"; 
    private static final String SECURITY_TOKEN_HEADER = "X-Token"; 
    private String token = null; 

    protected CustomAuthenticationFilter() { 
    super("/"); 
    } 

    @Override 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
    HttpServletRequest request = (HttpServletRequest) req; 
    HttpServletResponse response = (HttpServletResponse) res; 

    this.token = request.getParameter(SECURITY_TOKEN_KEY); 
    // or this.token = request.getHeader(SECURITY_TOKEN_HEADER); 

    if (request.getAttribute(FILTER_APPLIED) != null) { 
     chain.doFilter(request, response); 
     return; 
    } 

    request.setAttribute(FILTER_APPLIED, Boolean.TRUE); 

    if(request.getParameter(actionParameter) !=null && 
     request.getParameter(actionParameter).equals("logout")) { 
     SecurityContextHolder.clearContext(); 
     return; 
    } 

    if (!requiresAuthentication(request, response)) { 
     chain.doFilter(request, response); 
     return; 
    } 

    Authentication authResult; 
    try { 
     authResult = attemptAuthentication(request, response); 
     if (authResult == null) { 
     return; 
     } 
    } catch (AuthenticationException failed) { 
     unsuccessfulAuthentication(request, response, failed); 
     return; 
    } 

    try { 
     successfulAuthentication(request, response, chain, authResult); 
    } catch (NestedServletException e) { 
     if(e.getCause() instanceof AccessDeniedException) { 
     unsuccessfulAuthentication(request, response, new LockedException("Forbidden")); 
     } 
    } 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { 

    AbstractAuthenticationToken userAuthenticationToken = authUserByToken(this.token); 
    if(userAuthenticationToken == null) 
     throw new AuthenticationServiceException(MessageFormat.format("Error | {0}", "Bad Token")); 

    return userAuthenticationToken; 
    } 

    private AbstractAuthenticationToken authUserByToken(String tokenRaw) { 
    AbstractAuthenticationToken authToken = null; 
    try { 
     // check your input token, identify the user 
     // if success create AbstractAuthenticationToken for user to return 
     // eg: 
     authToken = new UsernamePasswordAuthenticationToken(username, userHash, userAuthorities); 

    } catch (Exception e) { 
     logger.error("Error during authUserByToken", e); 
    } 
    return authToken; 
    } 

    @Override 
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, 
              Authentication authResult) throws IOException, ServletException { 
    SecurityContextHolder.getContext().setAuthentication(authResult); 

    getSuccessHandler().onAuthenticationSuccess(request, response, authResult); 
    } 

} 

и пользовательские SuccessHandler как этого

public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { 

    @Override 
    protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) { 
    return request.getServletPath(); 
    } 

    @Override 
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { 
    request.getRequestDispatcher(request.getServletPath()).forward(request, response); 
    } 
} 

и провод его в весенней конфигурации

<?xml version="1.0" encoding="UTF-8"?> 
<b:beans 
    xmlns="http://www.springframework.org/schema/security" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:b="http://www.springframework.org/schema/beans" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:sec="http://www.springframework.org/schema/security" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd 
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd 
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> 

    <context:annotation-config/> 
    <context:component-scan base-package="com.your.path" /> 

    <aop:aspectj-autoproxy/> 

    <global-method-security pre-post-annotations="enabled" secured-annotations="enabled" proxy-target-class="true" 
          access-decision-manager-ref="accessDecisionManager"/> 

    <http entry-point-ref="restAuthenticationEntryPoint" use-expressions="true" 
     auto-config="true" access-decision-manager-ref="accessDecisionManager"> 
    <custom-filter ref="restFilter" position="PRE_AUTH_FILTER"/> 
    <logout/> 
    </http> 

    <b:bean id="restAuthenticationEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/> 

    <b:bean id="restFilter" class="com.your.path.CustomAuthenticationFilter"> 
    <b:property name="authenticationSuccessHandler" ref="mySuccessHandler"/> 
    </b:bean> 

    <b:bean id="mySuccessHandler" class="com.your.path.CustomAuthenticationSuccessHandler"/> 

    <b:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"> 
    <b:property name="allowIfAllAbstainDecisions" value="true"/> 
    <b:property name="decisionVoters"> 
     <b:list> 
     <b:bean class="org.springframework.security.access.vote.RoleVoter"> 
      <b:property name="rolePrefix" value=""/> 
     </b:bean> 
     <b:bean class="org.springframework.security.access.vote.AuthenticatedVoter" /> 
     </b:list> 
    </b:property> 
    </b:bean> 

</b:beans> 

это должно помочь.

+0

Нет ли фильтра проверки подлинности на токене на весенней безопасности? – Rafael

4

Вы можете сделать это с помощью следующей боб весной безопасности TimedKeyBasedPersistenceTokenService

<bean name="tokenService" class="com.digipos.security.core.token.TimedKeyBasedPersistenceTokenService"> 
    <property name="tokenLifeInMinutes" value="15000"/> 
    <property name="serverSecret" value="1234567"/> 
    <property name="serverInteger" value="15062013"/> 
    <property name="pseudoRandomNumberBits" value="7"/> 
    <property name="secureRandom" ref="secureRandom"/> 
</bean> 


<bean name="secureRandom" class="java.security.SecureRandom"> 
    <property name="seed" value="122"/> 
</bean> 

Помимо этого вы также должны

использовать PreAuthenticatedAuthenticationProvider

и entry-point-ref атрибут <http> в Http403ForbiddenEntryPoint боба

+0

Меня очень интересует эта аутентификация на основе токенов, но не понимает отношения с PreAuthenticatedAuthenticationProvider ... не нужно ли проверять токен для аутентификации? ... Можете ли вы подробнее рассказать об этом? – Rafael

1

Я нашел более простой способ:

Мое решение работает для аутентификации по токенам и формирует аутентификацию, но вы можете легко отключить один из них, если хотите.

Мой фильтр похож на фильтр Романа, но мне не нужен чек, если у пользователя есть доступ к определенному ресурсу, а также без выхода из системы -> передано в springSecurity.

Auth фильтр:

public class TokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 

private static final String SECURITY_TOKEN_KEY = "token"; 
private static final String SECURITY_TOKEN_HEADER = "X-Token"; 

public TokenAuthenticationFilter() { 

    super("/"); 
} 

@Override 
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 

    HttpServletRequest request = (HttpServletRequest) req; 
    HttpServletResponse response = (HttpServletResponse) res; 

    String token = request.getParameter(SECURITY_TOKEN_KEY); 
    // or this.token = request.getHeader(SECURITY_TOKEN_HEADER); 

    if (token != null) { 

     Authentication authResult; 
     try { 
      authResult = attemptAuthentication(request, response, token); 
      if (authResult == null) { 
       notAuthenticated(request, response, new LockedException("User Not found")); 
       return; 
      } 
     } catch (AuthenticationException failed) { 
      notAuthenticated(request, response, failed); 
      return; 
     } 

     try { 
      successfulAuthentication(request, response, chain, authResult); 
      return; 
     } catch (NestedServletException e) { 
      logger.error(e.getMessage(), e); 
      if (e.getCause() instanceof AccessDeniedException) { 
       notAuthenticated(request, response, new LockedException("Forbidden")); 
       return; 
      } 
     } 
    } 
    chain.doFilter(request, response);// return to others spring security filters 
} 

public void notAuthenticated(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { 

    response.sendRedirect("http://www.google.ro"); 
    // unsuccessfulAuthentication(request, response, failed); 
} 

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response, String token) throws AuthenticationException, IOException, ServletException { 

    AbstractAuthenticationToken userAuthenticationToken = authUserByToken(token); 
    if (userAuthenticationToken == null) 
     throw new AuthenticationServiceException(MessageFormat.format("Error | {0}", "Bad Token")); 

    return userAuthenticationToken; 
} 

private AbstractAuthenticationToken authUserByToken(String tokenRaw) { 

    AbstractAuthenticationToken authToken = null; 
    try { 
     // check your input token, identify the user 
     // if success create AbstractAuthenticationToken for user to return 
     // eg: 
     // authToken = new UsernamePasswordAuthenticationToken(username, userHash, userAuthorities); 
     // authToken = new UsernamePasswordAuthenticationToken(tokenRaw, authToken,) 
     logger.info("token received = " + tokenRaw); 
     // obtain user by your methods 
     // if (user != null) { 
     // SecurityUser securityUser = new SecurityUser(user); 
     // return new PreAuthenticatedAuthenticationToken(securityUser, securityUser.getPassword(), securityUser.getAuthorities()); 
     // } 
    } catch (Exception e) { 
     logger.error("Error during authUserByToken", e); 
    } 
    return authToken; 
} 

@Override 
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException, ServletException { 

    SecurityContextHolder.getContext().setAuthentication(authResult); 

    new CustomAuthenticationSuccessHandler().onAuthenticationSuccess(request, response, authResult); 
} 

@Override 
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { 

    logger.error("No TOKEN PROVIDED"); 
    return null; 
    } 

} 

то все, что вам нужно сделать, чтобы отобразить этот фильтр настраивая его в springSecurity (addFilterBefore), это не должны быть отображены в сервлет конфигурации.

 http.authorizeRequests().antMatchers("/login*").permitAll(); 
     http.authorizeRequests().antMatchers("/register*").permitAll(); 

     http.authorizeRequests().antMatchers("/admin/**").hasAnyAuthority("ROLE_ADMIN", "ROLE_USER");// 

     http.authorizeRequests().and().formLogin()// 
       .loginPage("/login")// 
       .successHandler(successHandler())// 
       .failureUrl("/login?error").permitAll()// 
       .and().logout()// 
       .logoutUrl("/logout").logoutSuccessUrl("/login?logout").permitAll()// 
       .and().rememberMe().key(applicationName + "_key").tokenValiditySeconds(2419200); // remember me for 2 weeks 

     http.addFilterBefore(new TokenAuthenticationFilter(), AnonymousAuthenticationFilter.class); 
+0

У меня есть вопрос обо всем этом? Когда на сервере создается токен, что генерирует токен и как он хранится/сохраняется на бэкэнд? Сколько времени для этого? И когда мы получаем запрос AJAX на бэкэнд, с токеном ... Я вижу, что у нас есть код для поиска этого токена из магазина токенов, это правильно?Когда маркер генерируется на бэкэнд и сохраняется, когда мы отправляем токен в интерфейс, вы храните его в качестве файла cookie? Что делать, если файлы cookie отключены? Благодаря! – tjholmes66

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