授权服务是基于Spring Security的,因此需要在目中引入两个依赖:
前者ؓ SecurityQ后者ؓSecurity的OAuth2扩展?/p>
在启动类中添?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">@EnableAuthorizationServer注解Q?br />
完成q些我们的授权服务最基本的骨架就已经搭徏完成了。但是要惌通整个流E,我们必须分配 client_id
, client_secret
才行。Spring Security OAuth2的配|方法是~写@Configuration
cȝ?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">AuthorizationServerConfigurerAdapterQ然后重?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">void configure(ClientDetailsServiceConfigurer clients)ҎQ如Q?br />
讉K授权面Q?br />
此时览器会让你输入用户名密码,q是因ؓ Spring Security 在默认情况下会对所有URLdBasic Auth认证。默认的用户名ؓuser
, 密码是随机生成的Q在控制台日志中可以看到?/p>
画风虽然很简陋,但是基本功能都具备了。点?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">Authorize后,览器就会重定向到百度,q带?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">code参数Q?/p>
拿到code
以后Q就可以调用
来换?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">access_token了:
q回如下Q?br />
到此我们最最基本的授权服务就搭徏完成了。然而,q仅仅是个demoQ如果要在生产环境中使用Q还需要做更多的工作?/p>
把授权服务器中的数据存储到数据库中ƈ不难Q因?Spring Cloud Security OAuth 已经为我们设计好了一套Schema和对应的DAO对象。但在用之前,我们需要先对相关的cL一定的了解?/p>
Spring Cloud Security OAuth2通过DefaultTokenServices
cL完成token生成、过期等 OAuth2 标准规定的业务逻辑Q?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">DefaultTokenServices又是通过TokenStore
接口完成对生成数据的持久化。在上面的demo中,TokenStore
的默认实CؓInMemoryTokenStore
Q即内存存储?对于Client信息Q?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">ClientDetailsService接口负责从存储仓库中d数据Q在上面的demo中默认用的也是InMemoryClientDetialsService
实现cR说到这里就能看出,要想使用数据库存储,只需要提供这些接口的实现cd可。庆q的是,框架已经为我们写好JDBC实现了,?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">JdbcTokenStore?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">JdbcClientDetailsService?/p>
要想使用q些JDBC实现Q首先要。框架ؓ我们提前设计好了schema, 在github上:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
在用这套表l构之前要注意的是,对于MySQL来说Q默认徏表语句中主键是varchar(255)cdQ在mysql中执行会报错Q原因是mysql对varchar主键长度有限制。所以这里改?28卛_。其ơ,语句中会有某些字DؓLONGVARBINARY
cdQ它对应mysql?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">blobcdQ也需要修改一下?/p>
数据库徏好后Q下一步就是配|框架用JDBC实现。方法还是编?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">@Configurationcȝ?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">AuthorizationServerConfigurerAdapterQ?br />
完成q些后,框架׃中间生的数据写到mysql中了?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">oauth_client_details是client表,可以直接在该表中d记录来添加client:
q里不得不说 Spring 设计有一个奇葩地的方。注意看oauth_access_token
表是存放讉K令牌的,但是q没有直接在字段中存放token。Spring 使用OAuth2AccessToken
来抽象与令牌有关的所有属性,在写入到数据库时Q?strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; outline: 0px; font-size: 16px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">Spring该对象通过JDK自带的序列化机制序列成字?/strong>直接保存C该表?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">token字段中。也是_如果只看数据表你是看不出access_token
的值是多少Q过期时间等信息的。这q资源服务器的实现带来了麻烦。我们的资源提供方ƈ没有使用Spring SecurityQ也不想引入 Spring Security 的Q何依赖,q时候就只能?nbsp;DefaultOAuth2AccessToken
的源码copy到资源提供方的项目中Q然后读?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">token字段q反序列化还原对象来获取token信息。但是如果这样做q会遇到反序列化兼容性的问题Q具体解x法参考我另一博?http://blog.csdn.net/neosmith/article/details/52539614
x一个能在生产环境下使用的授权服务就搭徏好了。其实我们在实际使用时应该适当定制JdbcTokenStore
?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">ClientDetailsService来实适应业务需要,甚至可以直接?开始实现接口,完全不用框架提供的实现。另外,Spring 直接?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">DefaultOAuth2AccessToken序列化成字节保存到数据库中的设计Q我认ؓ是非怸合理的。或许设计者的初衷是保?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">access_tokenQ但是通过加密的方法也可以实现Q完全不应该直接扔字节。不q通过定制TokenStore
接口Q我们可以用自q表结构而不拘惔于默认实现?br />
http://blog.csdn.net/tracker_w/article/category/6360121
http://blog.csdn.net/neosmith/article/details/52539927
Feign是一U声明式、模板化的HTTP客户端。在Spring Cloud中用Feign, 我们可以做到使用HTTPhq程服务时能与调用本地方法一L~码体验Q开发者完全感知不到这是远E方法,更感知不到这是个HTTPh。比如:
开发者通过service.findByGroupId()
p完成发送HTTPh和解码HTTPq回l果q封装成对象的过E?/p>
Z让Feign知道在调用方法时应该向哪个地址发请求以及请求需要带哪些参数Q我们需要定义一个接口:
A: @FeignClient
用于通知Feignlg对该接口q行代理(不需要编写接口实?Q用者可直接通过@Autowired
注入?/p>
B: @RequestMapping
表示在调用该Ҏ旉要向/group/{groupId}
发?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">GETh?/p>
C: @PathVariable
?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">SpringMVC中对应注解含义相同?/p>
Spring Cloud应用在启动时QFeign会扫描标?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">@FeignClient注解的接口,生成代理Qƈ注册到Spring容器中。生成代理时Feign会ؓ每个接口Ҏ创徏一?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">RequetTemplate对象Q该对象装了HTTPh需要的全部信息Q请求参数名、请求方法等信息都是在这个过E中定的,Feign的模板化׃现在q里?/p>
在本例中Q我们将Feign与Eureka和Ribbonl合使用Q?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">@FeignClient(name = "ea")意ؓ通知Feign在调用该接口Ҏ时要向Eureka中查询名?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">ea的服务,从而得到服务URL?/p>
Feign方法签名中Ҏ参数对象序列化ؓh参数攑ֈHTTPh中的q程Q是q码器(Encoder)完成的。同理,HTTP响应数据反序列化为java对象是由解码?Decoder)完成的?/p>
默认情况下,Feign会将标有@RequestParam
注解的参数{换成字符串添加到URL中,没有注解的参数通过Jackson转换成json攑ֈh体中。注意,如果?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">@RequetMapping中的method
请求方式指定ؓPOST
Q那么所有未标注解的参数会被忽略,例如Q?br />
此时因ؓ声明的是GETh没有h体,所?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">obj参数׃被忽略?/p>
在Spring Cloud环境下,Feign的Encoder*只会用来~码没有d注解的参?。如果你自定义了Encoder, 那么只有在编?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">obj参数时才会调用你的Encoder。对于Decoder, 默认会委托给SpringMVC中的MappingJackson2HttpMessageConverter
c进行解码。只有当状态码不在200 ~ 300之间时ErrorDecoder才会被调用。ErrorDecoder的作用是可以ҎHTTP响应信息q回一个异常,该异常可以在调用Feign接口的地方被捕获到。我们目前就通过ErrorDecoder来Feign接口抛出业务异常以供调用者处理?/p>
Feign在默认情况下使用的是JDK原生?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">URLConnection发送HTTPhQ没有连接池Q但是对每个地址会保持一个长q接Q即利用HTTP?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">persistence connection 。我们可以用Apache的HTTP Client替换Feign原始的http client, 从而获取连接池、超时时间等与性能息息相关的控制能力。Spring Cloud?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">Brixtion.SR5版本开始支持这U替换,首先在项目中声明Apache HTTP Client?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">feign-httpclient依赖Q?br />
然后?code style="box-sizing: border-box; font-family: "Source Code Pro", monospace; font-size: 13.5px; padding: 2px 4px; color: #3f3f3f; white-space: nowrap; border-radius: 0px; margin: 0px; border: 0px; outline: 0px; vertical-align: baseline; word-break: break-word; background: rgba(128, 128, 128, 0.0745098);">application.properties中添加:
通过FeignQ?我们能把HTTPq程调用对开发者完全透明Q得C调用本地Ҏ一致的~码体验。这一点与阉KDubbo中暴露远E服务的方式cMQ区别在于Dubbo是基于私有二q制协议Q而Feign本质上还是个HTTP客户端。如果是在用Spring Cloud Netflix搭徏微服务,那么Feign无疑是最佳选择?br />
http://blog.csdn.net/tracker_w/article/category/6360121
http://blog.csdn.net/neosmith/article/details/52449921