Appearance
组织授权与审计平台对接文档
文档说明
本文档将指导您快速接入“组织授权与审计平台”,以快速获得平台用户登录能力,资源整合能力。本文档分为三个部分,分别包括原理说明,对接操作,相关资源。
文档版本v1.3
- v1.3 修正一些标识符的写法
- v1.2 提供springboot,shiro-spring-boot对接方案
- v1.1 相关例子完善
- v1.0 初版撰写
目录
一、技术原理
1.1 基于OAuth2.0协议实现的开放认证
OAuth2.0协议是目前互联网上使用最广泛的授权协议。该协议被广泛应用于腾讯开放平台,微信开放平台,支付宝开放平台,微博开放平台等,是经历过市场实践和考验的标准化协议。
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials)
其中,授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动,全程不会把通信暴露在前端,我们采用的就是这种模式。
我们的服务端基于Spring Cloud微服务架构,采用Spring Security实现鉴权,以Spring Security OAuth2为基础进行高度定制化开发,实现了系统与系统之间的客户端授权模式,授权平台与网关服务的密码模式,以及认证服务器和第三方应用的授权码模式。
1.2 基于Filter实现的开放认证客户端
Spring的OAuth2实现提供了很优秀的SDK,但是高度依赖Spring Security,且不利于我们的业务定制开发,所以我们自己开发了一套完整的客户端授权封装。这就是OAuth Client。OAuth Client经过几次迭代已经趋于稳定,可以在线上稳定的运行。
环境和标准
目前我们只提供了Java客户端,基于标准的J2EE模式进行封装,依赖Servlet的App容器得以运作。暂时不支持基于NIO模型运行的容器,如Netty。
侵入性和系统影响
为了不影响贵系统的现有业务,我们使用Filter的方式无侵入的拦截OAuth的认证请求,不影响原功能的URL,所以请放心使用。 对接时,请依据您的环境,选择合适的高级封装SDK快速接入。我们根据常用的鉴权框架和应用框架,提供了各种组件。
几个内置的uri需要注意:
- ${您的网站}/oauth/callback : 这是内置Servlet提供的回调地址。用户先访问系统,跳转到认证中心后, 将会作为回调地址,由SDK接受参数并自动获取token。
- ${认证中心}/login : 这是认证中心的登录地址
全局过滤器Filter(由SDK提供)
SDK提供了默认的过滤器,会对贵方的服务端请求进行全量过滤,原理是通过判断token的有效性来决定放行, 如果token不存在或者无效,将会自动重定向到授权页面,交给用户授权登录。这些均只需要托管即可
1.3 数据同步原理
为了让贵系统的用户能够纳入统一认证中心,我们需要定时同步您的用户数据。
同步用户数据的操作不需要您进行实现,我们会定时的,主动的,以安全的加密模式拉取您的用户。这部分功能的侵入性非常低,对于接入而言,您只需要告诉我们用户是怎么查询的,还有您的用户信息是如何映射到我们的统一数据模型中即可。
平台服务器使用PBE算法(Password Based Encryption,基于口令加密)进行加密,内部的口令使用ClientSecret,以随机数列保证秘钥随机性,所有加解密过程都在服务器完成,最终使用REST的方式进行发送和接收。
二、快速接入指南
前置工作
申请您的ClientId和ClientSecret
请确认您对接的系统已经在认证中心注册,需要提供:
外网可访问的地址
您的系统id(建议自定义,如敏感,建议使用Base64编码) 在此步结束后,您应该已经拥有两个字段:
ClientId、ClientSecret这两个字段非常重要,是系统对接的关键。
确认您的运行环境
SDK原生支持使用Maven或Gradle构建的项目,如果您的项目未使用依赖管理,我们将提供 lib依赖包打包下载。
对于Spring环境,您需要JDK1.7及以上版本。Spring环境经过原生封装,有很好的的接入体验。
其他的应用框架未原生支持,但是都支持接入,接入过程要比上述框架繁杂,望知悉。
2.1 SpringBoot集成
如果您的系统基于SpringBoot实现,您需要定义配置,实现相关转换逻辑,并提供用户查询方法。您可以通过以下三步快速接入:
2.1.1 运行环境和准备工作
- 请升级您的开发环境,保证至少为 JDK 1.8(Java 8)版本,低版本不支持
- 请确保项目引用的Servlet API版本为3.0以上。建议使用至少如tomcat8作为开发容器
- SDK 的 JavaDoc 地址:
您可以使用Maven或者Gradle构建您的项目,依赖如下:
Maven依赖
我们在Maven全球中央仓库发布了Maven依赖,请直接引入以快速接入我们的SDK。目前最新版本:1.0.7
xml
<dependencies>
<dependency>
<groupId>group.flyfish.oauth</groupId>
<artifactId>oauth-spring-boot</artifactId>
<version>1.0.7</version>
</dependency>
</dependencies>Gradle依赖
nginx
dependencies {
compile "group.flyfish.oauth:oauth-spring-boot:1.0.7"
}2.1.2 配置您的OAuth客户端
如果您使用SpringBoot,SDK默认会检测您classpath下的oauth.yml作为默认配置文件,您也可以在spring默认的配置文件中注入配置,如application.properties或application.yml。
配置看起来像这样:
yaml
oauth:
client:
client-id: my-app # 您申请的clientId
client-secret: $1$RuldJVuF$nca1fNnjHQaHCRpMYcc.p1 # 您申请的clientSecret
local-url: http://60.221.255.208:8087 # 您系统的外网访问地址
server-url: http://220.194.160.2:8088 # 组织授权服务端地址
redirect-uri: http://60.221.255.208:8087/oauth/callback # 非必需,您的外网回调地址
user-authorization-uri: http://60.221.255.204:8088/login # 非必需,组织授权服务端登录地址,需要内外网转换必需大多数情况下,您的配置文件只需要包含:
yaml
oauth:
client:
client-id: my-app
client-secret: $1$MU1BZm/Y$Lg.zzRk35VYpqk8.IcWSM0
local-url: http://60.221.255.208:8087
server-url: http://220.194.160.2:8088除了设置OAuth客户端配置信息之外,您还需要排除 /oauth/** 路径下的鉴权判定,因为该路径被SDK用来做授权处理,很多问题都是因为没有排除鉴权导致的。
2.1.3 使用配置类实现您的逻辑
2.1.3.1 使用注解启用默认的配置扫描
请在您的启动类上添加@SpringBootOAuth注解以启用配置扫描。
2.1.3.2 实现相关配置类
实现配置类,以添加Session登录态转换,用户模型转换,用户同步相关能力对接。您有两种选择:
选择一 【推荐】添加OAuthConfig配置类,使用@Bean实现相关配置类
您可以方便的用@Bean实现相关配置类,所有的实现都统一管理,便于维护,还能方便的在方法参数注入需要的查询Service。
下面是demo中附带的实现源码,仅供参考。在您实现的时候,请注意替换相关泛型和转换逻辑为您自己系统的逻辑。
java
import ...
@Configuration
public class OAuthConfig {
/**
* SSO会话转换器,提供登录态转换
*
* @return 实例化的内部类
*/
@Bean
public SSOSessionConverter<User> ssoSessionConverter() {
return new SSOSessionConverter<User>() {
@Override
public boolean convert(HttpSession session, User userInfo) {
if (null == userInfo) {
// 用户未成功转换,session转换失败
return false;
}
// 简单的设置一个属性,标识已经登录
session.setAttribute("user", userInfo);
return true;
}
@Override
public boolean isComplete(HttpSession session) {
// 判断用户是否已经鉴权过,返回系统内部的登录态
return session.getAttribute("user") != null;
}
@Override
public String expectRedirectUri(HttpServletRequest request) {
// 期望的跳转路径。如果您想要在认证成功后跳转特定路径,请填写uri。如无必要,请保持留空
// 注意,如果授权中心未配置合法跳转url,这里定义的url可能会无效,建议配置的地址和平台注册客户端的首页地址一致
return null;
}
};
}
/**
* 用户同步提供者,提供用户列表查询和用户信息转换
*
* @return 实例化的bean
*/
@Bean
public SyncUserProvider<User> syncUserProvider(UserService userService, DepartService departService) {
return new AbstractUserProvider<User>() {
@Override
protected LocalUser transform(User domain) {
// 转换本地用户到统一的用户结构
return LocalUser.builder()
// 关键的outerId,必需包含,作为系统对接的依据,内容为本地用户的id
.outerId(String.valueOf(domain.getId()))
.name(domain.getName())
.comment(domain.getSign())
.phone(domain.getPhone())
.username(domain.getUsername())
.organization(Optional.ofNullable(domain.getDepartIds()).map(departIds -> departIds
.stream()
.map(departService::getById)
.map(Depart::getFullName)
.collect(Collectors.toList())
).orElse(Collections.emptyList()))
.build();
}
@Override
protected List<User> getLocalUsers() {
// 查询本地用户(全部可分享用户)
return userService.getByFilter(User.create());
}
};
}
/**
* 用户转换器,提供用户查询和转换
*
* @return 实例化的bean
*/
@Bean
public UserConverter<User> userConverter(UserService userService) {
// 直接返回用户转换逻辑,从封装的用户实体中利用outerId获取本地用户实体
return new UserConverter<User>() {
@Override
public User convert(LocalUser localUser) {
return userService.getById(Long.valueOf(localUser.getOuterId()));
}
};
}
}选择二 实现相关配置类,而不是使用@Bean
相对的,如果您不喜欢使用@Bean的方式实现,您可以单独实现以下接口或抽象类,并用@Component或@Service标注他们。
com.flyfish.oauth.configuration.OAuth2SsoUserService<T>com.flyfish.oauth.configuration.SSOSessionConverter<T>com.flyfish.oauth.configuration.sync.user.AbstractUserProvider<T>
其中的泛型 <T> 都是您系统中实际的用户类型
2.1.3.3 在授权中心对用户进行授权,测试
您可以登录组织授权与审计平台,在用户授权管理模块对您的系统用户进行授权测试。届时会为您开放权限。
对接开始后,会陆续维护FAQ,以解决问题。
2.2 SpringMVC集成
SpringMVC提供了简单的封装类,对配置实体和配置加载进行了简单的封装,您可以引入以下依赖:
xml
<dependency>
<groupId>group.flyfish.oauth</groupId>
<artifactId>oauth-spring</artifactId>
<version>1.0.7</version>
</dependency>以下提供两种方案供大家参考。
准备工作需要您确认jdk>=1.7.0,spring4.3以上。
2.2.1 【推荐】使用注解集成
2.2.1.1 开启配置类扫描
请确认已经在web.xml中添加您的配置类扫描。如果没有指定,请指定到您项目的config包下,如:
xml
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 使用基于注解的上下文配置,不必要请不要改动您自己的,如果您使用的是xml的话 -->
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<!-- 添加配置类路径,默认扫描,最先加载 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.xxx.xxxx.config</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>2.2.1.2 开启注解驱动
首先请在您的spring.xml中开启注解驱动,使用配置类或者已经开启的请忽略。
xml
<mvc:annotation-driven />2.2.1.3 配置您的客户端
请在您的资源目录下添加配置文件以快速配置客户端。如放到src/main/resources/oauth.properties下。
properties
# 是否开启审计功能
oauth.client.audit=true
# 您申请的clientId
#oauth.client.clientId=flyfish
oauth.client.clientId=test
# 您申请的clientSecret
#oauth.client.clientSecret=$1$q0rj6rbB$sjipzTV4gnjSRBfvoIkW0/
oauth.client.clientSecret=$1$c4IOwjVj$vVqRq9zQqMaGK5lMoh01h1
# 您的本地外网可访问的url
oauth.client.localUrl=http://localhost:8080
# 组织授权服务器地址
#oauth.client.serverUrl=http://localhost:8000
oauth.client.serverUrl=http://220.194.160.6:8088
# 授权回调地址,默认,不需要改
oauth.client.redirectUri=/oauth/callback
# 用户鉴权uri,默认,不需要改
oauth.client.userAuthorizationUri=/login
# 用户登出的uri,默认,不需要改
oauth.client.userLogoutUri=/logout
# 是否总是自动跳转,建议false,否则将无法使用原登录
oauth.client.autoRedirect=false
# 允许的url,标识平台鉴权过滤器放行的url,根据实际情况添加
oauth.client.allowUris=/authenticate,login.jsp2.2.1.3 创建配置类
使用原生的@Configuration配置类创建。请参考SpringBoot的相关配置,更方便的,请查看demo。
请在这里注入您的配置文件,添加配置启用注解@EnableSpringOAuth,实现用户转换服务OAuth2SsoUserService,实现用户登录态转换器SSOSessionConverter,实现用户同步方法SyncUserProvider中的transform和getLocalUsers。具体的请查看代码示例。
请在2.2.1.1小节中指定的配置路径下建立OAuthConfig.java
java
/**
* 开放认证配置类
* 本案例为了便于实现,使用注解驱动,配置文件位于oauth.properties中
*
* @author wangyu
*/
@Configuration
@EnableSpringOAuth
public class OAuthConfig {
/**
* 便捷的注入配置
*
* @return 结果
* @throws IllegalAccessException 异常访问异常
* @throws IOException io异常
* @throws InvocationTargetException 执行目标异常
*/
@Bean
public OAuthProperties oAuthProperties() throws IllegalAccessException, IOException, InvocationTargetException {
// 加载您存放配置文件的位置。已经为您封装内部的配置加载逻辑,无须修改就能调用。
return OAuthProperties.load("/oauth.properties");
}
/**
* 使用默认的用户服务包裹转换器,提供用户查询和转换
*
* @return 实例化的bean
*/
@Bean
public OAuth2SsoUserService<User> ssoUserService(final UserService userService) {
// 您需要实现从我们提供的LocalUser对象转换为您自己的用户对象。本案例中使用数据库查询获取最新的本地用户模型对象。
return new DefaultUserService<>(new UserConverter<User>() {
@Override
public User convert(LocalUser localUser) {
return userService.getById(Long.valueOf(localUser.getOuterId()));
}
});
}
/**
* SSO会话转换器,提供登录态转换
*
* @return 实例化的内部类
*/
@Bean
public SSOSessionConverter<User> ssoSessionConverter() {
return new SSOSessionConverter<User>() {
/**
* 转换session状态,请根据您自己的鉴权逻辑,模拟用户登录时的鉴权过程,获得鉴权状态
*
* @param session 会话
* @param userInfo 用户信息
* @return 结果,成功与否
*/
@Override
public boolean convert(HttpSession session, User userInfo) {
if (null == userInfo) {
// 用户未成功转换,session转换失败
return false;
}
// 简单的设置一个属性,标识已经登录
session.setAttribute("user", userInfo);
return true;
}
@Override
public boolean isComplete(HttpSession session) {
// 判断用户是否已经鉴权过,返回系统内部的登录态
return session.getAttribute("user") != null;
}
@Override
public String expectRedirectUri(HttpServletRequest request) {
// 期望的跳转路径。如果您想要在认证成功后跳转特定路径,请填写uri。如无必要,请保持留空
// 注意,如果授权中心未配置合法跳转url,这里定义的url可能会无效,建议配置的地址和平台注册客户端的首页地址一致
return null;
}
};
}
/**
* 用户同步提供者,提供用户列表查询和用户信息转换
*
* @return 实例化的bean
*/
@Bean
public SyncUserProvider<User> syncUserProvider(final UserService userService, final DepartService departService) {
return new AbstractUserProvider<User>() {
@Override
protected LocalUser transform(User domain) {
List<String> organizations = new ArrayList<>();
List<Long> departIds = domain.getDepartIds();
if (CollectionUtils.isNotEmpty(departIds)) {
for (Long departId : departIds) {
Depart depart = departService.getById(departId);
if (null != depart) {
organizations.add(depart.getFullName());
}
}
}
// 转换本地用户到统一的用户结构
return LocalUser.builder()
// 关键的outerId,必需包含,作为系统对接的依据,内容为本地用户的id
.outerId(String.valueOf(domain.getId()))
.name(domain.getName())
.comment(domain.getSign())
.phone(domain.getPhone())
.username(domain.getUsername())
.organization(organizations)
.build();
}
@Override
protected List<User> getLocalUsers() {
// 查询本地用户(全部可分享用户)
return userService.getByFilter(User.create());
}
};
}
}2.2.1.4 测试接入成果
您可以登录组织授权与审计平台,在用户授权管理模块对您的系统用户进行授权测试。届时会为您开放权限。
对接开始后,会陆续维护FAQ,以解决问题。
2.2.2 使用XML集成
除了使用注解的方式,您还可以使用xml。使用xml未提供例子,这里先提供您注入配置的方式,仅供参考。
使用xml实现配置信息。如下:
xml-dtd
<!--声明以注解的方式配置spring -->
<mvc:annotation-driven />
<!--引入配置文件-->
<context:property-placeholder location="classpath:oauth.properties"/>
<!--引入spring 和shiro集成的主配置文件-->
<bean id="oauthProperties" class="com.flyfish.oauth.spring.properties.OAuthProperties">
<property name="clientId" value="${oauth.client.clientId}" />
<property name="clientSecret" value="${oauth.client.clientSecret}" />
<property name="localUrl" value="${oauth.client.localUrl}" />
<property name="serverUrl" value="${oauth.client.serverUrl}" />
<property name="allowUris" value="${oauth.client.allowUris}" />
<property name="autoRedirect" value="${oauth.client.autoRedirect}" />
<property name="redirectUri" value="${oauth.client.redirectUri}" />
<property name="userAuthorizationUri" value="${oauth.client.userAuthorizationUri}" />
<property name="userLogoutUri" value="${oauth.client.userLogoutUri}" />
</bean>2.3 与shiro+springboot框架集成
如果您的系统使用shiro作为鉴权框架,那么对接起来将会事半功倍。我们提供了专门用于shiro的sdk,能够利用spring的注解式配置完成所有的对接事宜。
2.3.1 准备工作和系统需求
环境要求
JDK版本:JDK1.8及以上
依赖管理:Maven或者Gradle
框架依赖:Spring MVC 4.3以上,Spring Boot 2.0及以上,Shiro非早期版本(建议1.6.0,漏洞少)
容器类型:基于Servlet的Java应用容器,如Tomcat,Jetty等。
Maven依赖
我们在Maven全球中央仓库发布了Maven依赖,请直接引入以快速接入我们的SDK。目前最新版本:1.0.7。
xml
<dependencies>
<dependency>
<groupId>group.flyfish.oauth</groupId>
<artifactId>oauth-shiro-support</artifactId>
<version>1.0.7</version>
</dependency>
</dependencies>Gradle依赖
nginx
dependencies {
compile "group.flyfish.oauth:oauth-shiro-support:1.0.7"
}如果遇到依赖无法下载的问题,请删除缓存再试。
2.3.2 在启动类上引入配置
SpringBoot
如果您的项目基于SpringBoot,那么需要在启动类上添加@EnableShiroOAuth以开启配置扫描。
Spring MVC
如果您的项目未基于SpringBoot,您需要手动创建@Configuration类,并在该类上添加@EnableShiroOAuth。
当然,对于非注解扫描的项目,请在xml里声明我们的配置类 com.flyfish.oauth.shiro.ShiroOAuthConfiguration。
强烈建议开启mvc:annotation-driven以获得最大便利。
2.3.3 创建OAuthConfig配置类
为了快速接入,我们已经为您实现了大多数的必需接口。为了完成一些个性化的转换过程,需要实现以下几个interface以完成接入。推荐您使用Spring的@Configutaion配置类,结合@Bean快速实现,集中配置。
2.3.3.1 定义UserConverter,转换用户体系
用户转换器UserConverter。sdk已经帮助实现了用户服务以及与shiro的相关交互逻辑,所以您只需要实现用户转换逻辑即可。用户转换器从平台的用户模型转换为您的实际用户模型。
2.3.3.2 定义用户提供者,提供用户同步
用户提供者SyncUserProvider是用户同步的重要实现,需要您提供用户的转换,用户的查询两部分。
transform方法需要您将您的用户模型转换为组织授权平台可存储的用户模型(localUser)
getLocalUsers方法则是查询贵系统对组织授权平台可见的所有用户,查询出来的用户将由sdk组装并发送给服务器。
2.3.3.3 定义鉴权抽取器,从平台响应中抽取需要的内容
鉴权抽取器OAuthAuthorizationExtractor,需要您实现:
- 鉴权信息
AuthorizationInfo的抽取方法extract - 用户身份信息的抽取方法
extractPrincipal - 用户从组织授权平台登录成功后的回调
authenticateSuccess(可做原系统登录后的额外处理)
2.3.3.4 代码范例
java
@Configuration
public class OAuthConfig {
/**
* 用户转换器,从关联信息取出
*
* @return 结果
*/
@Bean
public UserConverter<User> userConverter(UserService userService) {
return localUser -> userService.getById(localUser.getOuterId());
}
/**
* 用户提供者,用于系统同步
*
* @param userService 用户服务
* @param deptService 部门服务
* @return 结果
*/
@Bean
public SyncUserProvider<User> userProvider(UserService userService, DeptService deptService) {
return new AbstractUserProvider<User>() {
@Override
protected LocalUser transform(User domain) {
return LocalUser.builder()
.outerId(String.valueOf(domain.getUserId()))
.username(domain.getAccount())
.phone(domain.getPhone())
.email(domain.getEmail())
.birthDay(domain.getBirthday())
.organization(Optional.ofNullable(domain.getDeptId())
.map(deptService::getById)
.map(Dept::getSimpleName)
.map(Arrays::asList)
.orElse(Collections.emptyList())
)
.gender("M".equals(domain.getSex()) ? Gender.MALE : Gender.FEMALE)
.name(domain.getName())
.build();
}
@Override
protected List<User> getLocalUsers() {
return userService.list();
}
};
}
/**
* shiro的鉴权解压
*
* @return 结果
*/
@Bean
public OAuthAuthorizationExtractor<User> authAuthorizationExtractor(JwtTokenApplier jwtTokenApplier) {
return new OAuthAuthorizationExtractor<User>() {
@Override
public AuthorizationInfo extract(PrincipalCollection principals) {
return AuthorizeUtils.getAuthInfo((ShiroUser) principals.getPrimaryPrincipal());
}
@Override
public Object extractPrincipal(User user) {
UserAuthService shiroFactory = UserAuthServiceServiceImpl.me();
return shiroFactory.shiroUser(user);
}
/**
* 模仿登录控制器,完成剩余工作
* @param user 用户
*/
@Override
public void authenticateSuccess(User user) {
RequestContext.getRequestResponse().ifPresent(((request, response) -> {
// 登录成功,将token放入Cookie,共享给bpm
String token = jwtTokenApplier.generate(user.getAccount());
jwtTokenApplier.apply(token, request, response);
ShiroKit.getSession().setAttribute("sessionFlag", true);
}));
}
};
}
}2.4 非Spring集成(J2EE)
本SDK额外提供了非Spring环境的对接解决demo,详细请下载demo查看,建议对接前先通读本文档。
三、部署和调试
由于OAuth2协议涉及到浏览器跳转请求,对于一般的j2ee项目来说没有任何问题 但是对于前后端完全分离的项目而言,需要额外的做一部分工作。
前后端分离下,前端通过ajax访问后端,对于应用而言,无法完成browser request。 我们使用曲线救国的方式,匹配特征和路径都放到web中间件去做
以下是本地化webpack代理配置
javascript
const devServer = {
index: '', // 重置index以代理根路径
...,
proxy: {
'/': {
target: 'http://localhost:8089',
changeOrigin: true,
bypass: function(req, res, proxyOptions) {
if (!req.query.oauth) {
return '/index.html';
}
},
},
'/oauth': {
target: 'http://localhost:8089',
ws: false,
changeOrigin: true,
},
}
};以下是nginx参考配置
editorconfig
server {
...
location / {
if ( $query_string ~* "oauth=1" ) {
# 当且仅当包含鉴权标记,才跳转
proxy_pass http://localhost:8089;
}
root ...;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
# 代理鉴权filter路径
location /oauth {
proxy_pass http://localhost:8089/;
proxy_set_header Host $host;
proxy_buffer_size 128k;
proxy_buffers 32 32k;
proxy_busy_buffers_size 128k;
}
}