All Downloads are FREE. Search and download functionalities are using the official Maven repository.

top.dcenter.ums.security.jwt.resolver.UmsBearerTokenResolver Maven / Gradle / Ivy

Go to download

ums-jwt feature: JWT 创建(通过接口自定义 Claims, 通过配置设置算法等), 校验(通过接口自定义校验规则), 刷新(自动刷新, 直接拒绝, 通过 refreshToken 刷新), 刷新的 JWT 使旧 JWT 失效引发的并发访问问题及黑名单.

There is a newer version: 2.2.42
Show newest version
/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package top.dcenter.ums.security.jwt.resolver;

import org.springframework.http.HttpHeaders;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.server.resource.BearerTokenError;
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import top.dcenter.ums.security.common.utils.UrlUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * The default {@link BearerTokenResolver} implementation based on RFC 6750.
 *
 * @author Vedran Pavic
 * @author YongWu zheng
 * @see RFC 6750
 * Section 2: Authenticated Requests
 * @since 5.1
 */
public final class UmsBearerTokenResolver implements BearerTokenResolver {

    private static final Pattern AUTHORIZATION_PATTERN = Pattern.compile("^Bearer (?[a-zA-Z0-9-._~+/]+=*)$",
                                                                         Pattern.CASE_INSENSITIVE);

    private final String requestParameterName;

    private boolean allowFormEncodedBodyParameter = false;

    private boolean allowUriQueryParameter = false;

    private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION;

    /**
     * 需要忽略的 url, 如: 通过 refreshToken 刷新 jwt uri, 登录的 uri. 支持 {@link AntPathMatcher} 模式.
     */
    private final Set ignoreUrls = new HashSet<>();

    private final AntPathMatcher matcher = new AntPathMatcher();

    public UmsBearerTokenResolver(@NonNull String requestParameterName, @Nullable String jwtByRefreshTokenUri) {
        this.requestParameterName = requestParameterName;
        this.ignoreUrls.add(jwtByRefreshTokenUri);
    }

    @Override
    public String resolve(HttpServletRequest request) {
        final String pathWithinApplication = UrlUtil.getUrlPathHelper().getPathWithinApplication(request);
        boolean anyMatch = ignoreUrls.stream()
                                     .anyMatch((ignoreUrl) -> matcher.match(ignoreUrl,
                                                                            pathWithinApplication));

        // 如果是匹配 ignoreUrls 则返回 null
        if (anyMatch) {
            return null;
        }

        String authorizationHeaderToken = resolveFromAuthorizationHeader(request);
        String parameterToken = resolveFromRequestParameters(request);
        if (authorizationHeaderToken != null) {
            if (parameterToken != null) {
                BearerTokenError error = BearerTokenErrors
                        .invalidRequest("Found multiple bearer tokens in the request");
                throw new OAuth2AuthenticationException(error);
            }
            return authorizationHeaderToken;
        }
        if (parameterToken != null && isParameterTokenSupportedForRequest(request)) {
            return parameterToken;
        }
        return null;
    }

    /**
     * 添加需要忽略解析 JWT token 的 url
     *
     * @param ignoreUrls 需要忽略解析 JWT token 的 urls, 支持 {@link AntPathMatcher} 模式.
     */
    public void addIgnoreUrls(Set ignoreUrls) {
        this.ignoreUrls.addAll(ignoreUrls);
    }

    /**
     * Set if transport of access token using form-encoded body parameter is supported.
     * Defaults to {@code false}.
     *
     * @param allowFormEncodedBodyParameter if the form-encoded body parameter is
     *                                      supported
     */
    public void setAllowFormEncodedBodyParameter(boolean allowFormEncodedBodyParameter) {
        this.allowFormEncodedBodyParameter = allowFormEncodedBodyParameter;
    }

    /**
     * Set if transport of access token using URI query parameter is supported. Defaults
     * to {@code false}.
     * 

* The spec recommends against using this mechanism for sending bearer tokens, and * even goes as far as stating that it was only included for completeness. * * @param allowUriQueryParameter if the URI query parameter is supported */ public void setAllowUriQueryParameter(boolean allowUriQueryParameter) { this.allowUriQueryParameter = allowUriQueryParameter; } /** * Set this value to configure what header is checked when resolving a Bearer Token. * This value is defaulted to {@link HttpHeaders#AUTHORIZATION}. *

* This allows other headers to be used as the Bearer Token source such as * {@link HttpHeaders#PROXY_AUTHORIZATION} * * @param bearerTokenHeaderName the header to check when retrieving the Bearer Token. * @since 5.4 */ public void setBearerTokenHeaderName(String bearerTokenHeaderName) { this.bearerTokenHeaderName = bearerTokenHeaderName; } private String resolveFromAuthorizationHeader(HttpServletRequest request) { String authorization = request.getHeader(this.bearerTokenHeaderName); String bearer = "bearer"; if (!StringUtils.startsWithIgnoreCase(authorization, bearer)) { return null; } Matcher matcher = AUTHORIZATION_PATTERN.matcher(authorization); if (!matcher.matches()) { BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed"); throw new OAuth2AuthenticationException(error); } return matcher.group("token"); } private String resolveFromRequestParameters(HttpServletRequest request) { String[] values = request.getParameterValues(requestParameterName); if (values == null || values.length == 0) { return null; } if (values.length == 1) { return values[0]; } BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request"); throw new OAuth2AuthenticationException(error); } private boolean isParameterTokenSupportedForRequest(HttpServletRequest request) { return ((this.allowFormEncodedBodyParameter && "POST".equals(request.getMethod())) || (this.allowUriQueryParameter && "GET".equals(request.getMethod()))); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy