通过令牌进行 Spring Security 身份验证 [英] Spring Security authentication via token

查看:49
本文介绍了通过令牌进行 Spring Security 身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有 API 的服务器.服务器受 Spring Security 保护.

I have a server with an API. Server is protected by Spring Security.

我想使用请求参数中的令牌从外部应用程序访问 API

I want to have an access to the API from an external applications using tokens in request parameters

首先,用户将访问一个服务,该服务为他提供一个令牌,然后使用该令牌访问 API.

Firstly user will go to a service which gives him a token and then access the API with this token.

但我想保留以前通过标准 Spring Security 解决方案访问 API 的权限.

But I want to preserve previous access to the API through standard Spring Security solutions.

那么,你能帮我吗,我该如何实现?

So, could you please help me, how can I implement this?

推荐答案

你需要像这样实现自定义的AuthenticationFilter

You need to implement custom AuthenticationFilter like this

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 像这样

and custom SuccessHandler like this

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);
  }
}

并将其连接到 spring 配置

and wire it in spring config

<?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>

这应该会有所帮助.

这篇关于通过令牌进行 Spring Security 身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆