spring security oauth2 授权服务器负载均衡解决方案

1.引言

本文所讲的内容是以spring security oauth2 与 spring cloud 为基础的,在微服务的构建中,将授权服务器注册在eureka上面。当客户端访问资源服务器的时候必须携带token进行认证和授权。如果我们在资源服务器上直接硬编码授权服务器地址,那么我们是不能够搭载高负载的授权服务器的,所以我们需要一个可以负载均衡的RestTemplate进行负载调用授权服务器。

2.创建负载均衡的RestTemplate

首先从源码查看授权服务器所使用的RestTemplate,可以发现资源服务器的RemoteTokenServices类中是直接创建一个RestTemplate并且设置了异常处理器进行异常处理(关键),但是这明显不是负载均衡的RestTemplate,所以我们需要重新设置一个负载均衡的RestTemplate

public class RemoteTokenServices implements ResourceServerTokenServices {

    ...

	private RestOperations restTemplate;

	public RemoteTokenServices() {
		restTemplate = new RestTemplate();
		((RestTemplate) restTemplate).setErrorHandler(new DefaultResponseErrorHandler() {
			@Override
			// Ignore 400
			public void handleError(ClientHttpResponse response) throws IOException {
				if (response.getRawStatusCode() != 400) {
					super.handleError(response);
				}
			}
		});
	}

     ...
}

首先定义一个负载均衡的RestTemplate(加上@LoadBalanced)

    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }

之后将这个负载均衡的RestTemplate设置到刚刚的RemoteTokenServices类中,记得将源码中的异常处理器也设置进去,否则当认证失败授权服务器返回400错误的时候,restTemplate将会抛出异常,如果没有异常处理器,那么此异常会被处理成500错误,这将难以使我们处理此错误。

@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public abstract class ResServerConfig extends ResourceServerConfigurerAdapter {

    ...    

    @Autowired(required = true)
    private RemoteTokenServices remoteTokenServices;

    @Autowired
    RestTemplate restTemplate;

   
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        super.configure(resources);
        if (StringUtils.isEmpty(oAuth2ClientProperties.getClientId())) {
            resources.resourceId(oAuth2ClientProperties.getClientId());
        }
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
            @Override
            // Ignore 400
            public void handleError(ClientHttpResponse response) throws IOException {
                if (response.getRawStatusCode() != 400) {
                    super.handleError(response);
                }
            }
        });
        if (Objects.nonNull(remoteTokenServices)) {
            remoteTokenServices.setRestTemplate(restTemplate);
            resources.tokenServices(remoteTokenServices);
        }
    }

    ...

}

3.在配置文件设置服务名称+端点地址

llg-oauth-server则是授权服务器在eureka注册的服务名称

security.oauth2.client.client-id=resource1
security.oauth2.client.client-secret=0
security.oauth2.client.user-authorization-uri=http://llg-oauth-server:9015/oauth/authorize
security.oauth2.client.grant-type=password
security.oauth2.client.scope=read
security.oauth2.client.access-token-uri=http://llg-oauth-server:9015/oauth/token
#需要jwt保存token的时候则需要配置下面的uri,拿到公共密钥
#security.oauth2.resource.jwt.key-uri=http://localhost:9015/oauth/token_key
#使用remoteServiec的时候则需要配置chekc端点
security.oauth2.resource.token-info-uri=http://llg-oauth-server:9015/oauth/check_token

4.总结

此次问题主要是我之前在思考如何搭载负载均衡的授权服务器的时候,只是重新set了一个负载均衡的RestTemplate,却没有仔细研究源码中对于异常处理器的重写。过了一段时间当我想研究如何进行token过期自动续签的时候,理想状态是返回401错误给我,但是没有想到的是返回了500错误,众所周知500错误是服务端错误,范围太广不适合分析处理。所以当我追着异常研究1天之后发现一切都是RestTemplate异常没有得到处理的缘故,最终导致此异常令spring mvc 返回500错误。所以在修改一些源码的时候切忌要弄清楚源码的流程和功能,不可盲目修改导致未知错误的发生。

猜你喜欢

转载自blog.csdn.net/m0_37834471/article/details/83187119