does not match one of the registered values异常原因及对应方式

异常现象

有时候使用OAuth2做SSO时,客户端访问统一认证中心,经过验证通过,重定向返回后可能会遇到下列问题
在这里插入图片描述
OAuth Error
error=“invalid_grant”, error_description=“Invalid redirect: http://localhost:8082/login does not match one of the registered values.”

解决方案

这个时候你需要检查你重定向地址的协议域名端口是否与在认证服务器注册的重定向地址保持一致。如果不一致就需要将多个域名配置到认证服务器。
例如我的认证服务器配置

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
     
        clients.inMemory()
                .withClient("client1")
                .secret(passwordEncoder.encode("client1"))
                .autoApprove(true)
                .redirectUris("http://127.0.0.1:8082/index")
                .scopes("admin")
                .accessTokenValiditySeconds(7200)
                .authorizedGrantTypes("authorization_code");

    }

这个时候如果我客户端访问下面两个地址都是可以重定向到统一认证中心的

  1. http://127.0.0.1:8082/index
  2. http://localhost:8082/index
    但是使用第二种就会出现下面的界面
    在这里插入图片描述
    原因就是我的host和配置的不一致,我的host配置的是127.0.0.1。

原因

我们从代码入手来解析一下为何会出现这种情况。具体逻辑在DefaultRedirectResolver.java中

	/**
	 * Attempt to match one of the registered URIs to the that of the requested one.
	 * 
	 * @param redirectUris the set of the registered URIs to try and find a match. This cannot be null or empty.
	 * @param requestedRedirect the URI used as part of the request
	 * @return redirect uri
	 * @throws RedirectMismatchException if no match was found
	 */
	private String obtainMatchingRedirect(Set<String> redirectUris, String requestedRedirect) {
     
		Assert.notEmpty(redirectUris, "Redirect URIs cannot be empty");
        // 重定向为空的话直接调用默认配置的重定向地址
		if (redirectUris.size() == 1 && requestedRedirect == null) {
     
			return redirectUris.iterator().next();
		}
        // 不为空的话,也就是我们出现异常的这种情况
		for (String redirectUri : redirectUris) {
     
		    // 判断重定向地址和配置的列表中的是否一致,都不一致的话就会抛出does not match one of the registered values这个异常
			if (requestedRedirect != null && redirectMatches(requestedRedirect, redirectUri)) {
     
				// Initialize with the registered redirect-uri
				UriComponentsBuilder redirectUriBuilder = UriComponentsBuilder.fromUriString(redirectUri);

				UriComponents requestedRedirectUri = UriComponentsBuilder.fromUriString(requestedRedirect).build();

				if (this.matchSubdomains) {
     
					redirectUriBuilder.host(requestedRedirectUri.getHost());
				}
				if (!this.matchPorts) {
     
					redirectUriBuilder.port(requestedRedirectUri.getPort());
				}
				redirectUriBuilder.replaceQuery(requestedRedirectUri.getQuery());		// retain additional params (if any)
				redirectUriBuilder.fragment(null);
				return redirectUriBuilder.build().toUriString();
			}
		}

		throw new RedirectMismatchException("Invalid redirect: " + requestedRedirect
				+ " does not match one of the registered values.");
	}

检测是否匹配的逻辑

	/**
	 * Whether the requested redirect URI "matches" the specified redirect URI. For a URL, this implementation tests if
	 * the user requested redirect starts with the registered redirect, so it would have the same host and root path if
	 * it is an HTTP URL. The port, userinfo, query params also matched. Request redirect uri path can include
	 * additional parameters which are ignored for the match
	 * 

* For other (non-URL) cases, such as for some implicit clients, the redirect_uri must be an exact match. * * @param requestedRedirect The requested redirect URI. * @param redirectUri The registered redirect URI. * @return Whether the requested redirect URI "matches" the specified redirect URI. */ protected boolean redirectMatches(String requestedRedirect, String redirectUri) { UriComponents requestedRedirectUri = UriComponentsBuilder.fromUriString(requestedRedirect).build(); UriComponents registeredRedirectUri = UriComponentsBuilder.fromUriString(redirectUri).build(); // scheme也就是协议是否一值 boolean schemeMatch = isEqual(registeredRedirectUri.getScheme(), requestedRedirectUri.getScheme()); // 携带的用户信息是否一值 boolean userInfoMatch = isEqual(registeredRedirectUri.getUserInfo(), requestedRedirectUri.getUserInfo()); // host也就是域名是否一致 boolean hostMatch = hostMatches(registeredRedirectUri.getHost(), requestedRedirectUri.getHost()); // 端口是否一致 boolean portMatch = matchPorts ? registeredRedirectUri.getPort() == requestedRedirectUri.getPort() : true; // path是否一致 boolean pathMatch = isEqual(registeredRedirectUri.getPath(), StringUtils.cleanPath(requestedRedirectUri.getPath())); // 携带参数是否一致 boolean queryParamMatch = matchQueryParams(registeredRedirectUri.getQueryParams(), requestedRedirectUri.getQueryParams()); // 全部一致才算通过 return schemeMatch && userInfoMatch && hostMatch && portMatch && pathMatch && queryParamMatch; }

你可能感兴趣的:(异常处理,oauth,sso)