微服务API开放受权平台的设计与实现

本文所介绍的项目是一个基于oath2协议的应用,实现的的功能逻辑与QQ互联微博开放平台相似,都是同一套认证受权流程。java

项目结构简单易懂,却不偷工减料,在学习完本文内容后,读者能够直接获取文中的项目代码用于学习或者copy到公司的生产项目中修改后使用,真正达到学以至用的目的。git

所涉及技术栈:github

  • java
  • springboot 2.0.1.RELEASE
  • spring security 2.0.1.RELEASE
  • spring cloud oauth2 2.0.0.M7
  • mybatis 2.0.1

本项目包括功能有web

  • 新用户
  1. 用户注册自动分配角色权限
  2. 用户只能访问本身所拥有的角色权限访问路径
  • 开放平台
  1. 用户能够申请获取客户ID和客户密钥
  2. 用户能够经过客户ID获取受权码
  3. 用户能够经过客户ID和密钥以及受权码获取access token 和referrsh token和scope
  • 资源api服务(order-service/open-api-service)
  1. 可自定义配置需受权url
  2. 可自定义配置受限url的访问scope
  3. 未受权用户或访问权限不足用户,页面提示相信息
  4. 用户经过access token 来访问对应url

项目概览

首先来看一下项目的结构图,了解项目的大体布局spring

  • .idea:idea工具生成的文件
  • docker: 存放Dockerfile文件用于构建容器镜像
  • config: 项目中关于spring security和web的配置
  • controller:请求控制器
  • entity: 对象实体类包
  • handler:逻辑处理类包
  • mapper:存放mybatis mapper接口类
  • service: 业务逻辑处理类
  • util: 通用的工具类
  • postman:postman工具的测试用例
  • sql:项目的初始化sql语句
  • templates: 页面模板文件

接下来正式介绍关于项目的细节,因为项目自己就已经有很多中文注释,因此在讲解的时候会收缩起一些代码的具体实现,若是读者不习惯能够在这里点在线比对阅读或者fork到本身的项目里阅读==> 项目代码sql

用户是如何被拦截认证的

  1. 自定类 SecurityConfig 继承了 WebSecurityConfigurerAdapter,说明SecurityConfig将会是一个 Http安全配置适配器
  2. 经过 @EnableWebSecurity打开了 HttpSecurity 的安全配置,则该类将生效

  1. 重写 WebSecurityConfigurerAdapter 的 configure(HttpSecurity http) 方法
  2. 指定哪里请求url是不须要拦截直接放行的
  3. 指定哪些请求是须要拦截校验的

  1. 重写 WebSecurityConfigurerAdapter 的 configure(AuthenticationManagerBuilder auth) 方法
  2. 指定处理认证的service服务类为 MyUserDetailsService
  3. 比对输入的密码和数据库中的用户密码是否一致

  1. 自定类 MyUserDetailsService 实现了 spring security的UserDetailsService 接口
  2. 重写 loadUserByUsername(String username) 方法, 其中username是页面传的属性和值,属性是固定的
  3. 获取用户权限表对应的权限详情,并把内容设置到 UserDetails.Authorities属性中
  4. 返回 UserDetails的子类 User

用户注册自动分配角色权限

用户注册则往用户表插入数据,同时往用户角色表也插入一份数据。
固然也能够设计的更复杂些,好比根据来源、时间、白名单、内部推荐等设置不一样的权限,读者可自行扩展。 docker

用户只能访问本身所拥有的角色权限访问路径

  1. 取出当前用户的全部权限
  2. 取出权限的权限标识字段,并包装成一个List 集合
  3. 保存包装的权限list集合到 UserDetails 对象中

  1. 取出全部权限表中内容
  2. http.authorizeRequests()获取当前的认证对象
  3. 把权限表中的内容所有设置到 authorizeRequests中, antMatchers表示拦截的url, hasAnyAuthority表示能够访问的权限标识
  4. 由于在上图中user已经设置了本身所拥有权限的权限标识,因此能够访问被拦截的url

用户能够申请获取客户ID和客户密钥

首先来看一下表结构,oauth_client_details 为spring cloud oath2自带的表, user_client_secret 为咱们本身建立的表 数据库

  1. 生成 OauthClientDetails 数据并保存至数据库中
  2. 获取当前登陆人信息,并绑定OauthClientDetails的clientId至user_client_secret表中

用户能够经过客户ID获取受权码

具体的实如今spring-security-oauth包中的, 非本项目内的自我实现api

客户ID获取受权码 请求url: http://localhost:8080/oauth/authorize?response_type=code&client_id=client_92&redirect_uri=http://localhost:8080/code安全

  1. 由于是要获取受权码,response_type=code为固定值
  2. 客户申请的客户ID
  3. oauth_client_details 表中的 web_server_redirect_uri

用受权码获取access_token

具体的实如今spring-security-oauth包中的 org.springframework.security.oauth2.provider.endpoint.TokenEndpoint类,有兴趣的同窗能够在里面进行debug调试

用受权码获取access_token 请求url: http://localhost:8080/oauth/token?grant_type=authorization_code&code=8fGtOV&client_id=client_92&client_secret=123456&redirect_uri=http://localhost:8080/code&scope=all

  1. 经过客户ID获取到的受权码
  2. 客户申请的客户ID
  3. 客户申请的客户ID配套的客户秘钥
  4. oauth_client_details 表中的 web_server_redirect_uri
  5. oauth_client_details 表中的 scope
# 出现以下相似错误标识code失效,从新在获取受权码操做便可
{
    "error": "invalid_grant",
    "error_description": "Invalid authorization code: iq30f9"
}
复制代码

商户id和商户秘钥获取accessToken和刷新accessToken

  • grant_type: 受权类型,这里设置为密码模式
  • username: 用户名
  • password: 用户密码
  • client_id: 申请获得的客户Id
  • client_secret: 申请获得的客户秘钥
  • scope:范围标识,取自 oauth_client_details 表中的 scope

刷新 accessToken

刷新 accessToken的 请求url: http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=4741d043-e202-4de0-ae21-4f5c7ec5626e&client_id=client_1&client_secret=123456

验证accessToken是否有效

验证accessToken的 请求url: http://localhost:8080/oauth/check_token?token=1131809b-ee12-4aea-9823-ea4454b96f2d

资源api服务

到了这里,咱们来看另外一个项目 order-service, 其实取名叫 order-api-resource 比较合适,不过也懒得改了。这个项目的结构与代码比较稀少,因此学习起来更为轻松。

如何自定义配置需拦截受权的url

经过 antMatchers()authenticated() 方法来配置,查看图中红框内的内容, 这些都是表明须要拦截验证的请求路径url,除了拦截请求外,还能够指定拦截请求方式,好比访问 /api/trade/ ,只对 POST 访问作拦截, GET 请求的访问一概放行。

如何自定义配置受限url的访问scope

经过 access() 方法指定访问的该 url 须要的 scope,取值为 oauth_client_details 表中的 scope 值, 若是scope值与代码中定义的不一致,则会出现以下错误:

未受权用户或访问权限不足用户,页面提示相应信息

用户如何经过 access token 来访问对应url

  1. 配置验证 accessToken 是否有效的服务地址,其实就是上面发放 accessToken 的服务
  2. 须要配置商户id和商户秘钥获取accessToken,用来经过的开发平台的校验。有的小伙伴可能奇怪了,文中上面也有介绍验证accessToken是否有效,可是并无须要验证登陆,这里为何要呢? 咱们来看下源码:

spring-security-oauth2-2.2.1.RELEASE-sources.jar 中的 RemoteTokenServices.java 用于远程调用 token 服务(开发平台)进行操做

  1. 由于给http header 设置了Authorization属性表示须要验证,因此取了上述配置中的 clientId 和 clientSecret,不然发送请求会被开放平台验证失败
  2. postForMap() 包装参数并执行请求发送

项目代码点这里

问题

/oauth/check_token 401

相关文章
相关标签/搜索