OAuth2.0过滤器链,如何在鉴权之前自定义传入一个token。

OAuth2.0过滤器链,如何在鉴权之前自定义传入一个token。_第1张图片
第5个过滤器时负责取到token进行验证。

一、解析查找 access_token
1、OAuth2AuthenticationProcessingFilter.tokenExtractor

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        boolean debug = logger.isDebugEnabled();
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;

        try {
            Authentication authentication = this.tokenExtractor.extract(request);
            if (authentication == null) {
                if (this.stateless && this.isAuthenticated()) {
                    if (debug) {
                        logger.debug("Clearing security context.");
                    }

                    SecurityContextHolder.clearContext();
                }

                if (debug) {
                    logger.debug("No token in request, will continue chain.");
                }
            } else {
                request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
                if (authentication instanceof AbstractAuthenticationToken) {
                    AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken)authentication;
                    needsDetails.setDetails(this.authenticationDetailsSource.buildDetails(request));
                }

                **Authentication authResult = this.authenticationManager.authenticate(authentication);**
                if (debug) {
                    logger.debug("Authentication success: " + authResult);
                }

                this.eventPublisher.publishAuthenticationSuccess(authResult);
                SecurityContextHolder.getContext().setAuthentication(authResult);
            }
        } catch (OAuth2Exception var9) {
            SecurityContextHolder.clearContext();
            if (debug) {
                logger.debug("Authentication request failed: " + var9);
            }

            this.eventPublisher.publishAuthenticationFailure(new BadCredentialsException(var9.getMessage(), var9), new PreAuthenticatedAuthenticationToken("access-token", "N/A"));
            this.authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(var9.getMessage(), var9));
            return;
        }

        chain.doFilter(request, response);
    }

调用的方法如下,

 protected String extractToken(HttpServletRequest request) {
        String token = this.extractHeaderToken(request);
        if (token == null) {
            logger.debug("Token not found in headers. Trying request parameters.");
            token = request.getParameter("access_token");
            if (token == null) {
                logger.debug("Token not found in request parameters.  Not an OAuth2 request.");
            } else {
                request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, "Bearer");
            }
        }

        return token;
    }

可以看出,两种方式取得token,一个时header的"Authorization"字段,一个时请求参数"access_token"。

这样,我们就需要在5号过滤器之前,给请求参数添加一个token。
自定义一个HttpServletRequest包装类:

/**
 * 自定义HttpServletRequest包装类,设置addParameter()方法。
 * @author sola
 */
public class ParameterRequestWrapper extends HttpServletRequestWrapper {

    private Map params = new HashMap();

    @SuppressWarnings("unchecked")

    public ParameterRequestWrapper(HttpServletRequest request) {

        // 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
        super(request);
        //将参数表,赋予给当前的Map以便于持有request中的参数
        this.params.putAll(request.getParameterMap());
    }
    //重载一个构造方法
    public ParameterRequestWrapper(HttpServletRequest request , Map extendParams) {
        this(request);
        //这里将扩展参数写入参数表
        addAllParameters(extendParams);


    }



    @Override

    public String getParameter(String name) {//重写getParameter,代表参数从当前类中的map获取

        String[]values = params.get(name);

        if(values == null || values.length == 0) {

            return null;

        }

        return values[0];

    }



    @Override
    public String[] getParameterValues(String name) {//同上

        return params.get(name);

    }



    public void addAllParameters(MapotherParams) {//增加多个参数

        for(Map.Entryentry : otherParams.entrySet()) {

            addParameter(entry.getKey() , entry.getValue());

        }

    }



    public void addParameter(String name , Object value) {//增加参数

        if(value != null) {

            if(value instanceof String[]) {

                params.put(name , (String[])value);

            }else if(value instanceof String) {

                params.put(name , new String[] {(String)value});

            }else {

                params.put(name , new String[] {String.valueOf(value)});

            }

        }

    }


然后自定义一个过滤器(项目中是从cookie中取出的token,OAuth2.0不支持直接对cookie进行鉴权):

/**
 * @author sola
 */
@Slf4j
public class HttpServletRequestCrossFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        log.info("\n\n" +
                "****************************************************************\n" +
                "******************   HttpServletRequestCrossFilter   ***********\n" +
                "****************************************************************\n");
        ParameterRequestWrapper parameterRequestWrapper = new ParameterRequestWrapper(request);
        Cookie accessToken = CookieUtils.getCookieByName(request, "access_token");
        log.info("cookie:{}", accessToken);
        if (accessToken != null && (accessToken.getValue()) != null && (accessToken.getValue()) != "") {
            String token = accessToken.getValue();
            log.info("token:{}", token);
              //从cookie中取出token,把它设置为请求参数;还有另一种方式,设置请求头Authorization = bearer+空格+token
            parameterRequestWrapper.addParameter("access_token",token);
        } else {
            log.info("没有token");
        }
        //把自定义的request传入过滤器链,进入下一个过滤器
        filterChain.doFilter(parameterRequestWrapper, response);
    }

}

把自定义的过滤器放入过滤器链,5号过滤器之前:

 @Override
    public void configure(HttpSecurity http) throws Exception {
      //省略其他设置
      ...........
        http.addFilterAfter(new HttpServletRequestCrossFilter(),HeaderWriterFilter.class);
    }

OK,搞定。

你可能感兴趣的:(spring,boot)