Spring Boot、Spring Security、Oauth2实现的权限控制和认证服务
基于Spring Boot、Spring Security、Oauth2等实现的权限控制和认证服务、支持第三方oauth授权和获取资源信息功能等
一.简介
该项目是基于Spring Boot搭建而成,通过Spring Security以及Spring Security Oauth2等,实现RBAC权限模型。其中包含了登录授权功能,以及第三方oauth授权和获取资源信息功能等。
二.OAuth2 协议的授权模式介绍
1.授权码模式(Authorization Code)
功能最完整,流程最严密的授权模式。国内各大服务提供商(微信、QQ、微博、淘宝 、百度)都采用此模式进行授权。可以确定是用户真正同意授权。
2.简化模式(Implicit)
令牌是发放给浏览器的,oauth客户端运行在浏览器中 ,通过JS脚本去申请令牌。不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌 ,不需要先获取授权码。
直接可以一次请求就可得到令牌,在 redirect_uri 指定的回调地址中传递令牌( access_token )。
3.密码模式(Resource Owner Password Credentials)
将用户名和密码传过去,直接获取 access_token 。用户同意授权动作是在第三方应用上完成 ,而不是在认证服务器上。第三方应用申请令牌时,直接带着用户名密码去向认证服务器申请令牌。这种方式认证服务器无法断定用户是否真的授权了,用户名密码可能是第三方应用盗取来的。
4.客户端证书模式(Client credentials)
用得少。当一个第三应用自己本身需要获取资源(而不是以用户的名义),而不是获取用户的资源时,客户端模式十分有用。
三.令牌管理策略介绍
- 内存存储采用的是 TokenStore 接口的默认实现类 InMemoryTokenStore , 开发时方便调试,适用单机版。
- RedisTokenStore 将令牌存储到 Redis 非关系型数据库中,适用于并发高的服务。
- JdbcTokenStore 基于 JDBC 将令牌存储到 关系型数据库中,可以在不同的服务器之间共享令牌。
- JwtTokenStore (JSON Web Token)将用户信息直接编码到令牌中,这样后端可以不用存储它,资源服务器可以直接解析获取用户数据。
四.为什么使用jwt令牌方式
当认证服务器和资源服务器不是在同一工程时, 要使用 ResourceServerTokenServices 去远程请求认证服务器来校验
令牌的合法性,如果用户访问量较大时将会影响系统的性能。
此时,采用 JWT 格式就可以解决上面的问题。
因为当用户认证后获取到一个JWT令牌,而这个 JWT 令牌包含了用户基本信息,客户端只需要携带JWT访问资源服
务器,资源服务器会通过事先约定好的算法进行解析出来,然后直接对 JWT 令牌校验,不需要每次远程请求认证服
务器完成授权。
当然并不是说jwt管理令牌是最优的方式,该方式也是存在着一定的不足的…
五.后端技术选型:
- Spring Boot 2.6.0
- Spring Security 2.6.6
- Spring Security oauth 2 2.2.6.RELEASE
- jjwt 0.7.0
- MyBatis 3.5.5
- MyBatis-Plus 3.4.3.4
- MySQL 5.1.30
- …
六.后端项目结构:
主要的三个模块项目
- platform-auth-server即认证服务
- platform-common即公共服务
- platform-resources-server即资源服务
micai
//认证服务
|-- platform-auth-server
| |-- platform-auth-server.iml
| |-- pom.xml
| |-- src
| |-- main
| |-- java
| | |-- org
| | |-- micai
| | |-- platform
| | |-- authserver
| | |-- AuthServerApplication.java
| | |-- bo //入参对象
| | | |-- UserQueryBo.java
| | |-- config //相关配置
| | | |-- AuthorizationServerConfiguration.java
| | | |-- JwtTokenEnhancer.java
| | | |-- PasswordEncoder.java
| | | |-- TokenConfig.java
| | | |-- WebSecurityConfig.java
| | |-- entity //相关实体类
| | | |-- Permission.java
| | | |-- Role.java
| | | |-- RolePermission.java
| | | |-- User.java
| | | |-- UserRole.java
| | |-- filter //相关过滤器
| | | |-- JWTAuthenticationFilter.java
| | | |-- JWTLoginFilter.java
| | |-- handler //相关处理器
| | | |-- CustomAuthenticationFailureHandler.java
| | | |-- Http401AuthenticationEntryPoint.java
| | | |-- MyMetaObjectHandler.java
| | |-- interceptor //相关拦截器
| | | |-- PlusInterceptor.java
| | |-- mapper //mapper文件
| | | |-- PermissionMapper.java
| | | |-- RoleMapper.java
| | | |-- RolePermissionMapper.java
| | | |-- UserMapper.java
| | | |-- UserRoleMapper.java
| | |-- provider //security相关提供器
| | | |-- CustomAuthenticationProvider.java
| | |-- service //相关service类
| | |-- PermissionService.java
| | |-- RolePermissionService.java
| | |-- RoleService.java
| | |-- UserRoleService.java
| | |-- UserService.java
| | |-- impl
| | |-- GrantedAuthorityImpl.java
| | |-- PermissionServiceImpl.java
| | |-- RolePermissionServiceImpl.java
| | |-- RoleServiceImpl.java
| | |-- UserDetailsServiceImpl.java
| | |-- UserRoleServiceImpl.java
| | |-- UserServiceImpl.java
| |-- resources
| |-- application-dev.yml
| |-- application-pro.yml
| |-- application.yml
//公共服务
|-- platform-common
| |-- platform-common.iml
| |-- pom.xml
| |-- src
| |-- main
| |-- java
| | |-- org
| | |-- micai
| | |-- platform
| | |-- common
| | |-- base //公共包
| | |-- WebStarterAutoConfig.java
| | |-- config //公共配置
| | | |-- MicaiPlatformOauthConfig.java
| | | |-- MicaiPlatformRequestMatcher.java
| | | |-- MicaiPlatformResourcesConfig.java
| | | |-- MicaiPlatformTokenConfig.java
| | |-- constant //常量和常枚举
| | | |-- ConstantCode.java
| | | |-- ConstantEnum.java
| | |-- controller //异常处理controller
| | | |-- ExceptionController.java
| | |-- exception //异常处理和自定义异常
| | | |-- GlobalExceptionHandler.java
| | | |-- MyAuthException.java
| | | |-- PlatformException.java
| | |-- result //自定义返回对象
| | | |-- Result.java
| | | |-- UploadResult.java
| |
| |-- resources
| |-- META-INF
| |-- spring.factories
//资源服务
|-- platform-resources-server
| |-- platform-resources-server.iml
| |-- pom.xml
| |-- src
| |-- main
| |-- java
| | |-- org
| | |-- micai
| | |-- platform
| | |-- resourcesserver
| | |-- ResourcesServerApplication.java
| | |-- bo //入参对象
| | | |-- MenuDelBo.java
| | | |-- MenuSaveBo.java
| | | |-- MenuUpdateBo.java
| | | |-- OrganDelBo.java
| | | |-- OrganFindBo.java
| | | |-- OrganSaveBo.java
| | | |-- OrganUpdateBo.java
| | | |-- PermissionDelBo.java
| | | |-- PermissionFindBo.java
| | | |-- PermissionMenuDelBo.java
| | | |-- PermissionMenuSaveBo.java
| | | |-- PermissionMenuUpdateBo.java
| | | |-- PermissionSaveBo.java
| | | |-- PermissionUpdateBo.java
| | | |-- RoleDelBo.java
| | | |-- RoleFindBo.java
| | | |-- RolePermissionDelBo.java
| | | |-- RolePermissionSaveBo.java
| | | |-- RolePermissionUpdateBo.java
| | | |-- RoleSaveBo.java
| | | |-- RoleUpdateBo.java
| | | |-- UserDelBo.java
| | | |-- UserFindBo.java
| | | |-- UserQueryBo.java
| | | |-- UserRoleDelBo.java
| | | |-- UserRoleSaveBo.java
| | | |-- UserRoleUpdateBo.java
| | | |-- UserSaveBo.java
| | | |-- UserUpdateBo.java
| | |-- config //相关配置类
| | | |-- CodeGenerator.java
| | | |-- PasswordEncoder.java
| | | |-- ResourceServerConfig.java
| | | |-- SiteOptions.java
| | | |-- SwaggerConfig.java
| | | |-- TokenConfig.java
| | | |-- WebSecurityConfig.java
| | |-- controller //表现层
| | | |-- BaseController.java
| | | |-- PermissionController.java
| | | |-- RoleController.java
| | | |-- RolePermissionController.java
| | | |-- UploadController.java
| | | |-- UserController.java
| | | |-- UserRoleController.java
| | |-- dto
| | | |-- UserAuthenticationDto.java
| | |-- entity
| | | |-- Permission.java
| | | |-- Role.java
| | | |-- RolePermission.java
| | | |-- User.java
| | | |-- UserRole.java
| | |-- filter //相关自定义过滤器
| | | |-- AuthHeaderFilter.java
| | | |-- JWTAuthenticationFilter.java
| | |-- handler //相关自定义处理器
| | | |-- Http401AuthenticationEntryPoint.java
| | | |-- MyMetaObjectHandler.java
| | |-- interceptor //相关拦截器
| | | |-- PlusInterceptor.java
| | |-- mapper
| | | |-- PermissionMapper.java
| | | |-- RoleMapper.java
| | | |-- RolePermissionMapper.java
| | | |-- UserMapper.java
| | | |-- UserRoleMapper.java
| | |-- provider //自定义security的提供器
| | | |-- CustomAuthenticationProvider.java
| | |-- service //相关的service
| | | |-- PermissionService.java
| | | |-- RolePermissionService.java
| | | |-- RoleService.java
| | | |-- UserRoleService.java
| | | |-- UserService.java
| | | |-- impl
| | | |-- GrantedAuthorityImpl.java
| | | |-- PermissionServiceImpl.java
| | | |-- RolePermissionServiceImpl.java
| | | |-- RoleServiceImpl.java
| | | |-- UserDetailsServiceImpl.java
| | | |-- UserRoleServiceImpl.java
| | | |-- UserServiceImpl.java
| | |-- utils //相关工具类
| | | |-- ApplicationUtil.java
| | | |-- AuthenticationManger.java
| | | |-- JwtHelper.java
| | | |-- MD5.java
| | |-- vo //返回前端对象
| | |-- OrganListVo.java
| | |-- PermissionListVo.java
| | |-- RoleListVo.java
| | |-- UserListVo.java
| |-- resources
| |-- application-dev.yml
| |-- application-pro.yml
| |-- application.yml
| |-- logback-spring.xml
|-- pom.xml
七.相关配置解读:
platform-auth-server:
micai-platform-auth:
#jwt-token登录相关配置
token:
#sign key
sign-key: micai-security-@Jwt!&Secret^#
#jwt 过期时间 单位:分钟
timeout: 60
# token名称
token-name: Authorization
# token前缀
token-prefix: Bearer
#oauth
oauth-auth:
#sign key
sign-key: micai-oauth2-@Jwt!&Secret^#
platform-resources-server:
micai-platform-auth:
#jwt相关配置
token:
#sign key
sign-key: micai-security-@Jwt!&Secret^#
#jwt 过期时间 单位:分钟
timeout: 60
# token名称
token-name: Authorization
# token前缀
token-prefix: Bearer
oauth-resources:
#sign key
sign-key: micai-oauth2-@Jwt!&Secret^#
#资源id
resource-ids: resources-server
#过滤器匹配路径 可以使用**
request-matcher:
- /demo/**
- /user/list
注意:
- 在oauth-resources. request-matcher下配置了的路径,代表该接口是需要携带oauth生成的access_token,其他默认的接口是需要携带登录生成的token
- 认证服务和资源服务配置的sign-key需要统一,不然会导致携带的token无法获取对应的资源
八.项目流程图:
本系统登录授权流程:
- 调用登录接口http://localhost:8080/login 返回token令牌
curl --location --request POST 'http://localhost:8080/login' \
--header 'Content-Type: application/json' \
--data-raw '{"username":"root","password":"root"}'
2.携带返回的token信息,访问需要获取资源接口
第三方应用授权流程:
授权码模式流程:
- 调用登录接口http://localhost:8080/login 返回token令牌
curl --location --request POST 'http://localhost:8080/login' \
--header 'Content-Type: application/json' \
--data-raw '{"username":"root","password":"root"}'
2.携带返回的token信息,访问oauth2授权接口,使用授权码模式web_server_redirect_uri地址并且拼接了授权码信息
curl --location --request GET 'http://localhost:8080/oauth/authorize?response_type=code&client_id=pc' \
--header 'Authorization: Bear xxxxxx'
如图所示:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9oH0CXda-1676523779300)(./doc/README.assets/image-20221228140017204.png)]
3.根据获取的授权码信息,调用获取access_token信息http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=pc&client_secret=admin&code=fQxVEU
curl --location --request POST 'http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=pc&client_secret=admin&code=fQxVEU'
返回的信息,如下:
{
"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb20iOiJsaXVjb25nIiwid2l0aCI6Im1pY2FpIiwiYXVkIjpbInJlc291cmNlcy1zZXJ2ZXIiXSwidXNlcl9uYW1lIjoiMS1yb290LVt",
"token_type": "bearer",
"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb20iOiJsaXVjb25nIiwid2l0aCI6Im1pY2FpIiwiYXVkIjpbInJlc291cmNlcy1zZXJ2ZXIiXSwidXNlcl9uYW1lIjoiMS1yb290LVtcIlJPTEVfcm9vdFwiLFwi",
"expires_in": 43199,
"scope": "pc",
"author": "liucong",
"jti": "cfc312f6-c38f-4670-9140-9985372cb7c9"
}
access_token:返回的token令牌,可以访问对应资源服务;
token_type:token类型,token前缀
expires_in:过期时间
scope:作用范围
author:通过实现TokenEnhancer,添加自定义信息
jti:jwt唯一标识
4.携带access_token信息,访问需要获取资源接口
密码模式流程:
调用接口地址
curl --location --request POST 'http://localhost:8080/oauth/token?username=root&password=root&grant_type=password&client_id=pc&client_secret=admin'
返回对象,返回相关的access_token 、 expires_in 、 scope 等相关信息,如授权码模式
简化模式流程:
调用接口地址
http://localhost:8080/oauth/authorize?response_type=token&client_id=pc
会跳转到指定的 redirect_uri ,回调路径携带着令牌 access_token 、 expires_in 、 scope 等相关信息,如图所示:
客户端模式流程:
该使用的情况比较少,大家可以自行体验
九.swagger地址:
我们使用的是knife4j
Knife4j · 集Swagger2及OpenAPI3为一体的增强解决方案. | Knife4j (xiaominfo.com)
platform-auth-server:http://localhost:8080/doc.html
platform-resources-server:http://localhost:8081/doc.html