├── .gitignore ├── README.md ├── authorization-code ├── README.md ├── authorization-code-authorization-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── AuthorizationCodeAuthorizationServerApp.java │ │ │ └── config │ │ │ ├── AuthorizationConfig.java │ │ │ └── SecurityConfig.java │ │ └── resources │ │ └── application.properties ├── authorization-code-client-resttemplate-jdbc │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── hellxz │ │ │ │ └── oauth2 │ │ │ │ ├── AuthorizationCodeClientApp.java │ │ │ │ ├── config │ │ │ │ ├── ClientAuthenticationManager.java │ │ │ │ ├── ClientUserDetailsService.java │ │ │ │ ├── OAuth2ClientProperties.java │ │ │ │ ├── OAuth2ServerProperties.java │ │ │ │ └── SecurityConfig.java │ │ │ │ ├── consts │ │ │ │ └── GrantType.java │ │ │ │ ├── dao │ │ │ │ └── ClientUserRepositories.java │ │ │ │ ├── domain │ │ │ │ └── ClientUser.java │ │ │ │ ├── dto │ │ │ │ └── TokenDTO.java │ │ │ │ ├── service │ │ │ │ ├── ClientUserService.java │ │ │ │ └── TokenService.java │ │ │ │ ├── utils │ │ │ │ └── SecurityUtils.java │ │ │ │ └── web │ │ │ │ ├── MainPageController.java │ │ │ │ └── vo │ │ │ │ └── UserInfo.java │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── sql │ │ │ └── create_table.sql │ │ │ └── templates │ │ │ ├── index.html │ │ │ └── user-info.html │ │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── hellxz │ │ └── oauth2 │ │ └── ClientUserTests.java ├── authorization-code-resource-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── AuthorizationCodeResourceServerApp.java │ │ │ ├── config │ │ │ └── ResourceConfig.java │ │ │ └── web │ │ │ ├── controller │ │ │ └── ResourceController.java │ │ │ └── vo │ │ │ └── UserVO.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── client-credentials ├── README.md ├── client-credentials-authorization-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── ClientCredentialsAuthorizationApp.java │ │ │ └── config │ │ │ ├── AuthorizationConfig.java │ │ │ └── SecurityConfig.java │ │ └── resources │ │ └── application.properties ├── client-credentials-client │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── ClientCredentialsClientApp.java │ │ │ ├── config │ │ │ ├── SecureConfig.java │ │ │ └── UaaProperties.java │ │ │ ├── dto │ │ │ └── UserDto.java │ │ │ ├── feign │ │ │ ├── UserFeignClient.java │ │ │ └── fallback │ │ │ │ └── UserFeignClientFallback.java │ │ │ ├── filter │ │ │ └── FeignTokenInterceptor.java │ │ │ ├── utils │ │ │ └── TokenUtils.java │ │ │ └── web │ │ │ └── UserController.java │ │ └── resources │ │ └── application.yml ├── client-credentials-resource-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── ClientCredentialsResourceServerApp.java │ │ │ ├── config │ │ │ └── ResourceServerConfig.java │ │ │ └── web │ │ │ ├── controller │ │ │ └── ResourceController.java │ │ │ └── vo │ │ │ └── UserVO.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── implicit ├── README.md ├── implicit-authorization-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── ImplicitAuthorizationServerApplication.java │ │ │ └── config │ │ │ ├── AuthorizationConfig.java │ │ │ └── SecurityConfig.java │ │ └── resources │ │ └── application.properties ├── implicit-resource-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── ImplicitResourceServerApp.java │ │ │ ├── config │ │ │ └── ResourceConfig.java │ │ │ └── web │ │ │ ├── controller │ │ │ └── ResourceController.java │ │ │ └── vo │ │ │ └── UserVO.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── jwt ├── README.md ├── jwt-authorization-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── JwtAuthorizationServerApp.java │ │ │ └── config │ │ │ ├── AuthorizationConfig.java │ │ │ └── SecurityConfig.java │ │ └── resources │ │ ├── application.properties │ │ └── hellxz-jwt.jks ├── jwt-resource-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── JwtResourceServerApp.java │ │ │ ├── config │ │ │ └── ResourceConfig.java │ │ │ └── web │ │ │ ├── controller │ │ │ └── ResourceController.java │ │ │ └── vo │ │ │ └── UserVO.java │ │ └── resources │ │ ├── application.properties │ │ └── public.cert └── pom.xml ├── password ├── README.md ├── password-authorization-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── PasswordAuthorizationApp.java │ │ │ └── config │ │ │ ├── AuthorizationConfig.java │ │ │ └── SecurityConfig.java │ │ └── resources │ │ └── application.properties ├── password-resource-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── hellxz │ │ │ └── oauth2 │ │ │ ├── PasswordResourceApp.java │ │ │ ├── config │ │ │ └── ResourceServerConfig.java │ │ │ └── web │ │ │ ├── controller │ │ │ └── ResourceController.java │ │ │ └── vo │ │ │ └── UserVO.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── pictures └── encoded-jwt3.png ├── pom.xml ├── redis-token-saved ├── README.md ├── pom.xml ├── redis-token-saved-authorization-server │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── hellxz │ │ │ │ └── oauth2 │ │ │ │ ├── RedisAuthorizationServer.java │ │ │ │ └── config │ │ │ │ ├── AuthorizationConfig.java │ │ │ │ └── SecurityConfig.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── hellxz │ │ └── auth2 │ │ └── RedisTokenSavedServerTest.java └── redis-token-saved-resource-server │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── hellxz │ │ └── oauth2 │ │ ├── RedisResourceServer.java │ │ ├── config │ │ └── ResourceServerConfig.java │ │ └── web │ │ ├── controller │ │ └── ResourceController.java │ │ └── vo │ │ └── UserVO.java │ └── resources │ └── application.yml └── uaa-interface-adapter-demo ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── github │ └── hellxz │ └── oauth2 │ └── demo │ ├── UaaAdapterApplication.java │ ├── config │ └── WebSecurityConfig.java │ ├── controller │ └── UaaAdapterController.java │ └── utils │ └── Response.java └── resources └── application.yml /.gitignore: -------------------------------------------------------------------------------- 1 | /spring-security-oauth2-learn.iml 2 | .idea 3 | *.iml 4 | **/target 5 | **/.classpath 6 | **/.project 7 | **/.settings -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-security-oauth2-learn 2 | ## 仓库说明 3 | 此项目用于学习Spring Security OAuth2,Demo使用的Api为5.2版本前的,现在提示已经废弃,ps:最初官方认为自己的授权服务器实现的太差就移除了,后来社区广泛需要授权服务器,官方又重新开发了`spring-security-oauth2-authorization-server 4 | 5 | 后续等官方授权服务器稳定后,本人会继续更新一个基于它的demo。相比此仓库的demo基于OAuth2.0实现,新的授权服务器是基于OAuth2.1协议的。 6 | 7 | 另外,本仓库均使用授权服务与资源服务分离的方式来编写demo,由于此二者放在同一服务时默认省了很多配置(资源服务器访问授权服务器进行校验token部分),对于后续应用会埋下许多坑,所以分离开来 8 | 9 | ## 基础演示demo功能说明 10 | > 基础Demo均使用内存保存token,仅用于测试 11 | 12 | - [x] authorization-code : 授权码模式 13 | 14 | - [x] client-credentials : 客户端模式 15 | 16 | - [x] implicit: 隐式模式(简化模式) 17 | 18 | - [x] password: 密码模式 19 | 20 | ## client端对接demo 21 | - [x] authorization-code/authorization-code-client-resttemplate-jdbc : 使用RestTemplate和数据库实现的授权码模式手动对接客户端,token保存到数据库 22 | - [x] uaa-interface-adapter-demo : 使用OAuth2提供的工具类,实现的客户端模式与密码模式的登录功能适配,也可以作为不显示使用/oauth/token端点的适配层,提升代码灵活性 23 | - [x] client-credentials/client-credentials-client: 实现一个客户端,如果调用其它服务的请求头中没有登录标识,使用客户端模式获取token,调用其它服务 24 | 25 | ## JWT 26 | > 使用rsa非对称加密,对称加密请参考本目录之前的提交 27 | 28 | - [x] jwt-authorization-server : 添加JWT实现token的授权服务器,这里开启了授权码与密码模式,支持refresh_token 29 | - [x] jwt-resource-server:资源服务器,本地校验jwt token,解析出用户信息 30 | 31 | ## 使用Redis存储token 32 | - [x] redis-token-saved-authorization-server : 使用password与授权码模式,支持刷新token的授权服务器,token保存到redis中 33 | - [x] redis-token-saved-resource-server : 使用redis校验token的资源服务器 34 | 35 | 36 | -------------------------------------------------------------------------------- /authorization-code/README.md: -------------------------------------------------------------------------------- 1 | # 授权码模式Demo 2 | 此文档测试对象为`authorization-code-authorization-server`和`authorization-code-resource-server` 3 | ## 1. 获取授权码 4 | 1. 用户(资源拥有者)浏览器访问 5 | `http://localhost:8080/oauth/authorize?client_id=client-a&redirect_uri=http://localhost:9001/callback&response_type=code&scope=read_user_info` 6 | 请求参数列表: 7 | - client_id=客户端id 8 | - redirect_uri=回调url 一定要与授权服务器配置保持一致,否则得不到授权码 9 | - response_type=code 授权码必须是code 10 | - scope=作用域 与授权服务器配置保持一致 11 | - state=加密串或状态标识(可选) 12 | 13 | 2. 使用hellxz用户登录,用户名hellxz,密码xyz 14 | > 这里使用授权服务器中的用户登录 15 | 16 | 3. 选择`Approve`,点`Authorize`提交, 完成授权操作 17 | 4. 服务器校验通过,在回调url参数后添加`?code=授权码`并重定向 18 | > 回调的url对应一个服务接口,接收授权码并使用其换取令牌,下边授权码换令牌步骤使用手动方式测试 19 | 20 | ## 2. 授权码换令牌 21 | > 换取令牌操作为服务器进行操作的,这里登录用户需要是客户端的标识与secret 22 | 23 | 1. 发送Post请求到`http://localhost:8080/oauth/token` 24 | 请求参数列表: 25 | - code=授权码 26 | - grant_type=authorization_code 27 | - redirect_uri=回调url 28 | - scope=作用域 29 | 30 | 请求头列表: 31 | - Authorization:Basic 经Base64加密后的username:password的字符串 32 | 33 | ``` 34 | curl -X POST \ 35 | http://localhost:8080/oauth/token \ 36 | -H 'Authorization: Basic Y2xpZW50LWE6Y2xpZW50LWEtc2VjcmV0' \ 37 | -d 'code=TJb4Pd&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A9001%2Fcallback&scope=read_user_info' 38 | ``` 39 | 40 | 获得令牌 41 | ```json 42 | { 43 | "access_token": "3ed92b8a-86f0-4ee1-b309-7db0b513f554", 44 | "token_type": "bearer", 45 | "expires_in": 43199, 46 | "scope": "read_user_info" 47 | } 48 | ``` 49 | 50 | ## 3. 校验Token 51 | 52 | 这里测试下授权服务的令牌校验端点`/oauth/check_token` 53 | 1. 发送Post请求`http://localhost:8080/oauth/check_token` 54 | 请求参数列表: 55 | - token=令牌 56 | 请求头参数: 57 | - Authorization=Basic Y2xpZW50LWE6Y2xpZW50LWEtc2VjcmV0 58 | 59 | ``` 60 | curl -X POST http://localhost:8080/oauth/check_token \ 61 | -H 'Authorization: Basic Y2xpZW50LWE6Y2xpZW50LWEtc2VjcmV0' \ 62 | -d 'token=3ed92b8a-86f0-4ee1-b309-7db0b513f554' 63 | ``` 64 | 65 | 返回请求体: 66 | ```json 67 | { 68 | "aud": [ 69 | "resource1" 70 | ], 71 | "active": true, 72 | "exp": 1574724686, 73 | "user_name": "hellxz", 74 | "client_id": "client-a", 75 | "scope": [ 76 | "read_user_info" 77 | ] 78 | } 79 | ``` 80 | 至此,我们确保了授权服务器的接口是正常的 81 | 82 | ## 4. 使用token访问受保护的资源 83 | 1. 发起请求`http://localhost:8081/user/hellxz001` 84 | 请求头参数: 85 | - Authorization:Bearer 令牌值 这里要注意的是Bearer与token间有一个空格 86 | 87 | ```bash 88 | curl -X GET http://localhost:8081/user/hellxz001 \ 89 | -H 'Authorization: Bearer ca3c1d03-67b8-4e39-b2b3-0d634f094610' 90 | ``` 91 | 92 | 返回结果 93 | ```json 94 | { 95 | "username": "hellxz001", 96 | "email": "hellxz001@foxmail.com" 97 | } 98 | ``` 99 | 100 | ## 授权码流程梳理 101 | 1. 用户通过客户端(浏览器等)的接口 客户端本地检查是否有令牌,没有则拼接请求授权服务器的url重定向给用户,有则使用令牌尝试访问,如果请求过期,重新走授权 102 | 2. 用户访问到授权服务器页面,用户登录,并进行授权 103 | 3. 授权通过,授权服务器返回code(授权码)到回调的客户端url上 104 | 4. 客户端收到授权码,带上授权码向授权服务器发起请求, 获取token 105 | 4. 授权服务器根据传递过来的客户端的client_id、client_secret、授权码进行校验,校验通过返回access_token 106 | 5. 客户端收到token,将token保存在本地,请求时带上token,接着自调用接口,访问资源服务器的资源 107 | 108 | > 这里暂未写客户端(浏览器这部分),通过手动获取资源以了解授权码模式整体授权流程 -------------------------------------------------------------------------------- /authorization-code/authorization-code-authorization-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | authorization-code 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | authorization-code-authorization-server 13 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-authorization-server/src/main/java/com/github/hellxz/oauth2/AuthorizationCodeAuthorizationServerApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * 授权服务器 入口 8 | * 9 | * @author hellxz 10 | */ 11 | @SpringBootApplication 12 | public class AuthorizationCodeAuthorizationServerApp { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(AuthorizationCodeAuthorizationServerApp.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-authorization-server/src/main/java/com/github/hellxz/oauth2/config/AuthorizationConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.crypto.password.PasswordEncoder; 6 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 7 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 10 | 11 | //授权服务器配置 12 | @Configuration 13 | @EnableAuthorizationServer //开启授权服务 14 | public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { 15 | 16 | @Autowired 17 | private PasswordEncoder passwordEncoder; 18 | 19 | @Override 20 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 21 | //允许表单提交 22 | security.allowFormAuthenticationForClients() 23 | .checkTokenAccess("isAuthenticated()"); 24 | } 25 | 26 | @Override 27 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 28 | // @formatter: off 29 | clients.inMemory() 30 | .withClient("client-a") //客户端唯一标识(client_id) 31 | .secret(passwordEncoder.encode("client-a-secret")) //客户端的密码(client_secret),这里的密码应该是加密后的 32 | .authorizedGrantTypes("authorization_code") //授权模式标识 33 | .scopes("read_user_info") //作用域 34 | .resourceIds("resource1") //资源id 35 | .redirectUris("http://localhost:9001/callback"); //回调地址 36 | // @formatter: on 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-authorization-server/src/main/java/com/github/hellxz/oauth2/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 10 | import org.springframework.security.crypto.password.PasswordEncoder; 11 | 12 | import java.util.Collections; 13 | 14 | @Configuration 15 | @EnableWebSecurity 16 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 17 | 18 | @Bean 19 | public PasswordEncoder passwordEncoder(){ 20 | return new BCryptPasswordEncoder(); 21 | } 22 | 23 | @Override 24 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 25 | // @formatter: off 26 | auth.inMemoryAuthentication() 27 | .withUser("hellxz") 28 | .password(passwordEncoder().encode("xyz")) 29 | .authorities(Collections.emptyList()); 30 | // @formatter: on 31 | } 32 | 33 | @Override 34 | protected void configure(HttpSecurity http) throws Exception { 35 | http.authorizeRequests() 36 | .anyRequest().authenticated() //所有请求都需要通过认证 37 | .and() 38 | .httpBasic() //Basic提交 39 | .and() 40 | .csrf().disable(); //关跨域保护 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-authorization-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/README.md: -------------------------------------------------------------------------------- 1 | # 接入授权码模式客户端使用RestTemplate实现 2 | ## 说明 3 | 这里使用RestTemplate作为客户端,对接我们的授权码模式的授权服务器和资源服务器,客户端token存储使用数据库实现(仅用作demo) 4 | ## 操作流程 5 | 1. 启动授权码授权服务器 6 | 2. 启动授权码资源服务器 7 | 3. 数据库修改并执行`resource/create_table.sql`,启动此项目 8 | 4. 访问`http://localhost:9001`点击`点此进入用户详情页` 9 | 5. 使用`hellxz`:`abc`登录,这里登录的是客户端服务器 10 | 6. 使用`hellxz`:`xyz`登录,这里登录的是授权服务器 11 | 7. 进行授权操作 12 | 8. 自动重定向到访问的资源页面 13 | ## 内部流程说明 14 | - 访问授权详情页时,由于资源被拦截,会弹出登录窗口,登录客户端用户 15 | - 进行用户详情页对应的controller,查数据库看`oauth2_client_db.client_user`表中是否有用户token 16 | - 如果有,使用此token尝试调用资源服务器,没有则去调用授权服务器,获取授权码 17 | - 授权服务器返回授权码到客户端的回调接口`/callback` 18 | - 回调接口中,使用授权码换取token,获取token后保存到数据库与当前security上下文 19 | - 重定向原来的页面,再走一次访问资源服务器调用,如果报错`HttpClientErrorException`,则捕获异常并重走授权(token已过期) 20 | - 最后一切正常,放置资源服务器得到的数据并跳转到页面,进行展示 -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | authorization-code 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | authorization-code-client-resttemplate-jdbc 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-thymeleaf 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-data-jpa 22 | 23 | 24 | mysql 25 | mysql-connector-java 26 | 27 | 28 | org.apache.commons 29 | commons-lang3 30 | 31 | 32 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/AuthorizationCodeClientApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | @SpringBootApplication 9 | public class AuthorizationCodeClientApp { 10 | public static void main(String[] args) { 11 | SpringApplication.run(AuthorizationCodeClientApp.class, args); 12 | } 13 | 14 | @Bean 15 | public RestTemplate restTemplate(){ 16 | return new RestTemplate(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/config/ClientAuthenticationManager.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import com.github.hellxz.oauth2.dao.ClientUserRepositories; 4 | import org.apache.commons.lang3.StringUtils; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.authentication.AuthenticationManager; 7 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 8 | import org.springframework.security.core.Authentication; 9 | import org.springframework.security.core.AuthenticationException; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class ClientAuthenticationManager implements AuthenticationManager { 15 | 16 | @Autowired 17 | private ClientUserDetailsService clientUserDetailsService; 18 | 19 | @Override 20 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 21 | UserDetails principal = (UserDetails) authentication.getPrincipal(); 22 | String username = principal.getUsername(); 23 | String password = principal.getPassword(); 24 | if (StringUtils.isAnyBlank(username, password)) { 25 | throw new RuntimeException("用户名与密码均不能为空"); 26 | } 27 | UserDetails userDetails = clientUserDetailsService.loadUserByUsername(username); 28 | if (!StringUtils.equals(password, userDetails.getPassword())) { 29 | throw new RuntimeException("密码输入不正确!"); 30 | } 31 | return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/config/ClientUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import com.github.hellxz.oauth2.dao.ClientUserRepositories; 4 | import com.github.hellxz.oauth2.domain.ClientUser; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | import org.springframework.security.core.userdetails.UserDetailsService; 8 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.Objects; 13 | 14 | @Service 15 | public class ClientUserDetailsService implements UserDetailsService { 16 | 17 | @Autowired 18 | private ClientUserRepositories clientUserRepositories; 19 | 20 | @Autowired 21 | private PasswordEncoder passwordEncoder; 22 | 23 | /** 24 | * 数据库查用户对象实现,这里不做权限控制 25 | */ 26 | @Override 27 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 28 | ClientUser clientUser = clientUserRepositories.findOneByUsername(username); 29 | if(Objects.isNull(clientUser)){ 30 | throw new UsernameNotFoundException("用户不存在"); 31 | } 32 | return clientUser; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/config/OAuth2ClientProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.apache.commons.lang3.builder.ToStringBuilder; 4 | import org.apache.commons.lang3.builder.ToStringStyle; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.annotation.PostConstruct; 11 | 12 | @Component 13 | @ConfigurationProperties(prefix = "oauth2.client") 14 | public class OAuth2ClientProperties { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(OAuth2ClientProperties.class); 17 | 18 | private String clientId; 19 | private String clientSecret; 20 | private String redirectUri; 21 | private String responseType; 22 | private String scope; 23 | 24 | @PostConstruct 25 | public void outputProperties(){ 26 | log.info("当前OAuth2客户端配置:{}", this); 27 | } 28 | 29 | public String getClientId() { 30 | return clientId; 31 | } 32 | 33 | public void setClientId(String clientId) { 34 | this.clientId = clientId; 35 | } 36 | 37 | public String getClientSecret() { 38 | return clientSecret; 39 | } 40 | 41 | public void setClientSecret(String clientSecret) { 42 | this.clientSecret = clientSecret; 43 | } 44 | 45 | public String getRedirectUri() { 46 | return redirectUri; 47 | } 48 | 49 | public void setRedirectUri(String redirectUri) { 50 | this.redirectUri = redirectUri; 51 | } 52 | 53 | public String getResponseType() { 54 | return responseType; 55 | } 56 | 57 | public void setResponseType(String responseType) { 58 | this.responseType = responseType; 59 | } 60 | 61 | public String getScope() { 62 | return scope; 63 | } 64 | 65 | public void setScope(String scope) { 66 | this.scope = scope; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/config/OAuth2ServerProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.apache.commons.lang3.builder.ToStringBuilder; 4 | import org.apache.commons.lang3.builder.ToStringStyle; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.annotation.PostConstruct; 11 | 12 | @Component 13 | @ConfigurationProperties(prefix = "oauth2.server") 14 | public class OAuth2ServerProperties { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(OAuth2ServerProperties.class); 17 | 18 | private String host; 19 | private String authorizeUrl; 20 | private String tokenUrl; 21 | private String checkTokenUrl; 22 | 23 | @PostConstruct 24 | public void outputProperties(){ 25 | log.info("当前OAuth2服务端配置:{}", this); 26 | } 27 | 28 | public String getHost() { 29 | return host; 30 | } 31 | 32 | public void setHost(String host) { 33 | this.host = host; 34 | } 35 | 36 | public String getAuthorizeUrl() { 37 | return authorizeUrl; 38 | } 39 | 40 | public void setAuthorizeUrl(String authorizeUrl) { 41 | this.authorizeUrl = authorizeUrl; 42 | } 43 | 44 | public String getTokenUrl() { 45 | return tokenUrl; 46 | } 47 | 48 | public void setTokenUrl(String tokenUrl) { 49 | this.tokenUrl = tokenUrl; 50 | } 51 | 52 | public String getCheckTokenUrl() { 53 | return checkTokenUrl; 54 | } 55 | 56 | public void setCheckTokenUrl(String checkTokenUrl) { 57 | this.checkTokenUrl = checkTokenUrl; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import com.github.hellxz.oauth2.dao.ClientUserRepositories; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.http.HttpMethod; 8 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 | import org.springframework.security.crypto.password.PasswordEncoder; 14 | 15 | import javax.sql.DataSource; 16 | 17 | @Configuration 18 | @EnableWebSecurity 19 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 20 | 21 | @Bean 22 | public PasswordEncoder passwordEncoder() { 23 | return new BCryptPasswordEncoder(); 24 | } 25 | @Autowired 26 | private ClientUserRepositories clientUserRepositories; 27 | 28 | @Autowired 29 | private ClientUserDetailsService clientUserDetailsService; 30 | 31 | @Autowired 32 | private DataSource dataSource; 33 | 34 | @Override 35 | protected void configure(HttpSecurity http) throws Exception { 36 | //@formatter:off 37 | http.authorizeRequests() 38 | //仅放通登录接口 39 | .antMatchers(HttpMethod.GET, "/", "/index", "/api/login", "/callback").permitAll() 40 | .anyRequest().authenticated() 41 | .and() 42 | .httpBasic(); 43 | //@formatter:on 44 | } 45 | 46 | @Override 47 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 48 | auth.userDetailsService(clientUserDetailsService); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/consts/GrantType.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.consts; 2 | 3 | public enum GrantType { 4 | /** 5 | * 授权码 6 | */ 7 | AUTHORIZATION_CODE("authorization_code"), 8 | /** 9 | * 简化模式 10 | */ 11 | IMPLICIT("implicit"), 12 | /** 13 | * 客户端模式 14 | */ 15 | CLIENT_CREDENTIALS("client_credentials"), 16 | /** 17 | * 用户密码模式 18 | */ 19 | PASSWORD("password"); 20 | 21 | private String code; 22 | GrantType(String code){ 23 | this.code = code; 24 | } 25 | 26 | public String getCode() { 27 | return code; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/dao/ClientUserRepositories.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.dao; 2 | 3 | import com.github.hellxz.oauth2.domain.ClientUser; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface ClientUserRepositories extends JpaRepository { 7 | ClientUser findOneByUsername(String username); 8 | } 9 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/domain/ClientUser.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.domain; 2 | 3 | import org.apache.commons.lang3.builder.ToStringBuilder; 4 | import org.apache.commons.lang3.builder.ToStringStyle; 5 | import org.springframework.security.core.GrantedAuthority; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.Entity; 10 | import javax.persistence.GeneratedValue; 11 | import javax.persistence.Id; 12 | import java.io.Serializable; 13 | import java.util.Calendar; 14 | import java.util.Collection; 15 | import java.util.Collections; 16 | 17 | @Entity(name = "client_user") 18 | public class ClientUser implements UserDetails, Serializable { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | @Id 23 | @GeneratedValue 24 | @Column(name = "id") 25 | private long id; 26 | @Column(name = "username") 27 | private String username; 28 | @Column(name = "password") 29 | private String password; 30 | @Column(name = "access_token") 31 | private String accessToken; 32 | @Column(name = "refresh_token") 33 | private String refreshToken; 34 | @Column(name = "validate_token_expire") 35 | private Calendar validateTokenExpire; 36 | 37 | public long getId() { 38 | return id; 39 | } 40 | 41 | public void setId(long id) { 42 | this.id = id; 43 | } 44 | 45 | public String getUsername() { 46 | return username; 47 | } 48 | 49 | @Override 50 | public boolean isAccountNonExpired() { 51 | return true; 52 | } 53 | 54 | @Override 55 | public boolean isAccountNonLocked() { 56 | return true; 57 | } 58 | 59 | @Override 60 | public boolean isCredentialsNonExpired() { 61 | return true; 62 | } 63 | 64 | @Override 65 | public boolean isEnabled() { 66 | return true; 67 | } 68 | 69 | public void setUsername(String username) { 70 | this.username = username; 71 | } 72 | 73 | @Override 74 | public Collection getAuthorities() { 75 | return Collections.emptyList(); 76 | } 77 | 78 | public String getPassword() { 79 | return password; 80 | } 81 | 82 | public void setPassword(String password) { 83 | this.password = password; 84 | } 85 | 86 | public String getAccessToken() { 87 | return accessToken; 88 | } 89 | 90 | public void setAccessToken(String accessToken) { 91 | this.accessToken = accessToken; 92 | } 93 | 94 | public String getRefreshToken() { 95 | return refreshToken; 96 | } 97 | 98 | public void setRefreshToken(String refreshToken) { 99 | this.refreshToken = refreshToken; 100 | } 101 | 102 | public Calendar getValidateTokenExpire() { 103 | return validateTokenExpire; 104 | } 105 | 106 | public void setValidateTokenExpire(Calendar validateTokenExpire) { 107 | this.validateTokenExpire = validateTokenExpire; 108 | } 109 | 110 | @Override 111 | public String toString() { 112 | return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/dto/TokenDTO.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.dto; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import org.apache.commons.lang3.builder.ToStringBuilder; 5 | import org.apache.commons.lang3.builder.ToStringStyle; 6 | 7 | /** 8 | * 授权成功token返回体 9 | */ 10 | public class TokenDTO { 11 | @JsonProperty("access_token") 12 | private String accessToken; 13 | @JsonProperty("refresh_token") 14 | private String refreshToken; 15 | @JsonProperty("token_type") 16 | private String tokenType; 17 | @JsonProperty("expires_in") 18 | private String expiresIn; 19 | @JsonProperty("scope") 20 | private String scope; 21 | 22 | public String getRefreshToken() { 23 | return refreshToken; 24 | } 25 | 26 | public void setRefreshToken(String refreshToken) { 27 | this.refreshToken = refreshToken; 28 | } 29 | 30 | public String getAccessToken() { 31 | return accessToken; 32 | } 33 | 34 | public void setAccessToken(String accessToken) { 35 | this.accessToken = accessToken; 36 | } 37 | 38 | public String getTokenType() { 39 | return tokenType; 40 | } 41 | 42 | public void setTokenType(String tokenType) { 43 | this.tokenType = tokenType; 44 | } 45 | 46 | public String getExpiresIn() { 47 | return expiresIn; 48 | } 49 | 50 | public void setExpiresIn(String expiresIn) { 51 | this.expiresIn = expiresIn; 52 | } 53 | 54 | public String getScope() { 55 | return scope; 56 | } 57 | 58 | public void setScope(String scope) { 59 | this.scope = scope; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/service/ClientUserService.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.service; 2 | 3 | import com.github.hellxz.oauth2.dao.ClientUserRepositories; 4 | import com.github.hellxz.oauth2.domain.ClientUser; 5 | import com.github.hellxz.oauth2.utils.SecurityUtils; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.Optional; 10 | 11 | @Service 12 | public class ClientUserService { 13 | 14 | @Autowired 15 | private ClientUserRepositories repositories; 16 | 17 | public void updateClientUser(ClientUser clientUser){ 18 | Optional userById = repositories.findById(clientUser.getId()); 19 | if(userById.isPresent()){ 20 | repositories.save(clientUser); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/service/TokenService.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.service; 2 | 3 | import com.github.hellxz.oauth2.config.OAuth2ClientProperties; 4 | import com.github.hellxz.oauth2.config.OAuth2ServerProperties; 5 | import com.github.hellxz.oauth2.consts.GrantType; 6 | import com.github.hellxz.oauth2.domain.ClientUser; 7 | import com.github.hellxz.oauth2.dto.TokenDTO; 8 | import com.github.hellxz.oauth2.web.vo.UserInfo; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.http.*; 11 | import org.springframework.stereotype.Component; 12 | import org.springframework.util.LinkedMultiValueMap; 13 | import org.springframework.util.MultiValueMap; 14 | import org.springframework.web.client.HttpClientErrorException; 15 | import org.springframework.web.client.RestTemplate; 16 | import org.springframework.web.servlet.ModelAndView; 17 | 18 | import java.io.UnsupportedEncodingException; 19 | import java.net.URI; 20 | import java.net.URLEncoder; 21 | import java.util.*; 22 | 23 | @Component 24 | public class TokenService { 25 | 26 | @Autowired 27 | private OAuth2ServerProperties auth2ServerProperties; 28 | 29 | @Autowired 30 | private OAuth2ClientProperties auth2ClientProperties; 31 | 32 | @Autowired 33 | private RestTemplate restTemplate; 34 | 35 | /** 36 | * 请求授权码url 37 | */ 38 | public String getAuthorizeUrl() { 39 | HashMap params = new HashMap<>(); 40 | params.put("client_id", auth2ClientProperties.getClientId()); 41 | params.put("redirect_uri", URLEncoder.encode(auth2ClientProperties.getRedirectUri())); 42 | params.put("response_type", auth2ClientProperties.getResponseType()); 43 | params.put("scope", URLEncoder.encode(auth2ClientProperties.getScope())); 44 | return buildUrlStr(auth2ServerProperties.getAuthorizeUrl(), params); 45 | } 46 | 47 | /** 48 | * 请求授权token的url 49 | */ 50 | public String getToken(String code) throws UnsupportedEncodingException { 51 | RequestEntity httpEntity = new RequestEntity<>(getHttpBody(code), getHttpHeaders(), HttpMethod.POST, URI.create(auth2ServerProperties.getTokenUrl())); 52 | ResponseEntity exchange = restTemplate.exchange(httpEntity, TokenDTO.class); 53 | if (exchange.getStatusCode().is2xxSuccessful()) { 54 | System.err.println(exchange.getBody()); 55 | return Objects.requireNonNull(exchange.getBody()).getAccessToken(); 56 | } 57 | throw new RuntimeException("请求令牌失败!"); 58 | } 59 | 60 | public void tryGetUserInfo(ModelAndView mv, ClientUser currentUser) { 61 | //正常请求资源服务器,获取用户信息 62 | HttpHeaders headers = new HttpHeaders(); 63 | headers.setBearerAuth(currentUser.getAccessToken()); 64 | RequestEntity> requestEntity 65 | = new RequestEntity<>(headers, HttpMethod.GET, URI.create("http://localhost:8081/user/jack")); 66 | ResponseEntity exchange = null; 67 | try{ 68 | //尝试访问资源 69 | exchange = restTemplate.exchange(requestEntity, UserInfo.class); 70 | }catch (HttpClientErrorException exception){ 71 | //未认证会报错,重定向到授权页面,获取新token 72 | mv.setViewName("redirect:" + getAuthorizeUrl()); 73 | return; 74 | } 75 | assert exchange != null; 76 | if (exchange.getStatusCode().is2xxSuccessful()) { 77 | UserInfo body = exchange.getBody(); 78 | mv.addObject("currentLoginUsername", currentUser.getUsername()); 79 | mv.addObject("user", body); 80 | } 81 | } 82 | 83 | private HttpHeaders getHttpHeaders() { 84 | HttpHeaders httpHeaders = new HttpHeaders(); 85 | httpHeaders.setBasicAuth(auth2ClientProperties.getClientId(), auth2ClientProperties.getClientSecret()); 86 | httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); 87 | httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); 88 | return httpHeaders; 89 | } 90 | 91 | private MultiValueMap getHttpBody(String code) throws UnsupportedEncodingException { 92 | MultiValueMap params = new LinkedMultiValueMap<>(); 93 | params.add("code", code); 94 | params.add("grant_type", GrantType.AUTHORIZATION_CODE.getCode()); 95 | params.add("redirect_uri", auth2ClientProperties.getRedirectUri()); 96 | params.add("scope", auth2ClientProperties.getScope()); 97 | return params; 98 | } 99 | 100 | /** 101 | * 构建url 102 | * 103 | * @param endpoint 服务器端点url 104 | * @param params 参数列表 105 | * @return 带参数的url 106 | */ 107 | private String buildUrlStr(String endpoint, Map params) { 108 | List keyValueParam = new ArrayList<>(params.size()); 109 | params.forEach((key, value) -> keyValueParam.add(key + "=" + value)); 110 | return endpoint + "?" + keyValueParam.stream().reduce((a, b) -> a + "&" + b).get(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/utils/SecurityUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.utils; 2 | 3 | import com.github.hellxz.oauth2.domain.ClientUser; 4 | import com.github.hellxz.oauth2.service.ClientUserService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.core.Authentication; 7 | import org.springframework.security.core.context.SecurityContext; 8 | import org.springframework.security.core.context.SecurityContextHolder; 9 | import org.springframework.security.core.userdetails.UserDetails; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | public class SecurityUtils { 14 | 15 | @Autowired 16 | private ClientUserService clientUserService; 17 | 18 | public UserDetails getCurrentUser(){ 19 | SecurityContext context = SecurityContextHolder.getContext(); 20 | Authentication authentication = context.getAuthentication(); 21 | Object principal = authentication.getPrincipal(); 22 | if(principal instanceof UserDetails){ 23 | return (UserDetails) principal; 24 | } 25 | return null; 26 | } 27 | 28 | /** 29 | * 更新token 30 | */ 31 | public void updateToken(String token){ 32 | SecurityContext context = SecurityContextHolder.getContext(); 33 | Authentication authentication = context.getAuthentication(); 34 | Object principal = authentication.getPrincipal(); 35 | if(principal instanceof ClientUser){ 36 | ClientUser clientUser = (ClientUser) principal; 37 | clientUser.setAccessToken(token); 38 | clientUserService.updateClientUser(clientUser); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/web/MainPageController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web; 2 | 3 | import com.github.hellxz.oauth2.domain.ClientUser; 4 | import com.github.hellxz.oauth2.service.TokenService; 5 | import com.github.hellxz.oauth2.utils.SecurityUtils; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | import org.springframework.web.client.RestTemplate; 12 | import org.springframework.web.servlet.ModelAndView; 13 | 14 | import java.io.UnsupportedEncodingException; 15 | 16 | /** 17 | * 页面控制器,本示例中所有controller都在这里 18 | */ 19 | @Controller 20 | public class MainPageController { 21 | 22 | @Autowired 23 | private RestTemplate restTemplate; 24 | 25 | @Autowired 26 | private TokenService tokenService; 27 | 28 | @Autowired 29 | private SecurityUtils securityUtils; 30 | 31 | /** 32 | * 主页 33 | */ 34 | @GetMapping(value = {"/", "/index"}) 35 | public String index(){ 36 | return "index"; 37 | } 38 | 39 | /** 40 | * 回调 41 | */ 42 | @GetMapping("/callback") 43 | public ModelAndView callback(@RequestParam("code") String code) throws UnsupportedEncodingException { 44 | String token = tokenService.getToken(code); 45 | if(StringUtils.isNotBlank(token)){ 46 | securityUtils.updateToken(token); 47 | return new ModelAndView("redirect:/user-info"); 48 | } 49 | throw new RuntimeException("请求超时"); 50 | } 51 | 52 | /** 53 | * 用于测试获取token与访问资源服务器资源的功能 54 | */ 55 | @GetMapping("/user-info") 56 | public ModelAndView userInfoPage(){ 57 | //获取当前登录的用户,这个用户对象中包含数据库中保存的token 58 | ClientUser currentUser = (ClientUser)securityUtils.getCurrentUser(); 59 | //不存在需要去走一次授权码模式流程 60 | if(null != currentUser && StringUtils.isBlank(currentUser.getAccessToken())){ 61 | //重定向到授权服务器进行授权, 先获取授权码 62 | return new ModelAndView("redirect:"+tokenService.getAuthorizeUrl()); 63 | } 64 | ModelAndView modelAndView = new ModelAndView("user-info"); 65 | //尝试获取资源 66 | tokenService.tryGetUserInfo(modelAndView, currentUser); 67 | return modelAndView; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/java/com/github/hellxz/oauth2/web/vo/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import org.apache.commons.lang3.builder.ToStringBuilder; 5 | import org.apache.commons.lang3.builder.ToStringStyle; 6 | 7 | public class UserInfo { 8 | @JsonProperty("username") 9 | private String username; 10 | @JsonProperty("email") 11 | private String email; 12 | 13 | public String getEmail() { 14 | return email; 15 | } 16 | 17 | public void setEmail(String email) { 18 | this.email = email; 19 | } 20 | 21 | public String getUsername() { 22 | return username; 23 | } 24 | 25 | public void setUsername(String username) { 26 | this.username = username; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9001 3 | 4 | spring: 5 | http: 6 | converters: 7 | preferred-json-mapper: jackson 8 | thymeleaf: 9 | cache: false 10 | datasource: 11 | driver-class-name: com.mysql.cj.jdbc.Driver 12 | url: jdbc:mysql://localhost:3306/oauth2_client_db?useSSL=false&useCharacterEncoding=utf-8 13 | username: root 14 | password: root 15 | jpa: 16 | properties: 17 | hibernate: 18 | hbm2ddl.auto: update 19 | dialect: org.hibernate.dialect.MySQL5InnoDBDialect 20 | show-sql: true 21 | 22 | oauth2: 23 | client: 24 | client-id: client-a 25 | client-secret: client-a-secret 26 | redirect_uri: http://localhost:${server.port}/callback 27 | response_type: code 28 | scope: read_user_info 29 | server: 30 | host: http://localhost:8080 31 | authorize-url: ${oauth2.server.host}/oauth/authorize 32 | token-url: ${oauth2.server.host}/oauth/token 33 | check-token-url: ${oauth2.server.host}/oauth/check_token 34 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/resources/sql/create_table.sql: -------------------------------------------------------------------------------- 1 | -- 创建数据库 2 | create database if not exists `oauth2_client_db` default character set utf8 collate utf8_general_ci; 3 | use oauth2_client_db; 4 | -- 创建client端用户,这里可以与授权服务登录用户名和密码不一致 5 | create table if not exists client_user 6 | ( 7 | id bigint auto_increment primary key, 8 | username varchar(32) not null, 9 | `password` varchar(64) not null, 10 | access_token varchar(256) default null, 11 | validate_token_expire datetime, 12 | refresh_token varchar(256) default null 13 | ); 14 | -- 每次启动清空上次用户表,仅用于测试 15 | truncate table client_user; 16 | -- 插入一个与授权服务器密码不一致的用户 17 | insert into client_user values (null,'hellxz','$2a$10$iAEfWxvrLKt6bhBdkNsdCeMn6JEqrS8c6MF/pbbeAeCxVrgkH92Re', null, null, null); 18 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 首页 6 | 7 | 8 | 点此进入用户详情页 9 | 10 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/main/resources/templates/user-info.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 用户详情页面 6 | 7 | 8 |
当前登录的用户为:

test

9 |
10 |
11 | 获得的用户信息为: 12 |
    13 |
  • 用户名:测试用户
  • 14 |
  • 密码:测试email
  • 15 |
16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-client-resttemplate-jdbc/src/test/java/com/github/hellxz/oauth2/ClientUserTests.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import com.github.hellxz.oauth2.dao.ClientUserRepositories; 4 | import com.github.hellxz.oauth2.domain.ClientUser; 5 | import org.junit.Assert; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.security.crypto.password.PasswordEncoder; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | import org.springframework.test.web.servlet.MockMvc; 14 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 15 | import org.springframework.web.context.WebApplicationContext; 16 | 17 | import javax.transaction.Transactional; 18 | import java.util.Calendar; 19 | import java.util.Date; 20 | 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest(classes = AuthorizationCodeClientApp.class) 23 | public class ClientUserTests { 24 | 25 | @Autowired 26 | private WebApplicationContext webApplicationContext; 27 | @Autowired 28 | private PasswordEncoder passwordEncoder; 29 | private MockMvc mockMvc; 30 | @Autowired 31 | private ClientUserRepositories clientUserRepositories; 32 | 33 | @Before 34 | public void init(){ 35 | mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 36 | } 37 | 38 | @Test 39 | @Transactional 40 | public void insertClientUserTest(){ 41 | ClientUser user = new ClientUser(); 42 | user.setUsername("刺客五六七"); 43 | user.setPassword("567"); 44 | user.setAccessToken("test"); 45 | user.setRefreshToken("test"); 46 | Calendar calendar = Calendar.getInstance(); 47 | calendar.setTime(new Date(System.currentTimeMillis() + 100000000L)); 48 | user.setValidateTokenExpire(calendar); 49 | ClientUser save = clientUserRepositories.save(user); 50 | Assert.assertNotNull(save); 51 | Assert.assertEquals(user.getUsername(), save.getUsername()); 52 | Assert.assertEquals(user.getPassword(), save.getPassword()); 53 | } 54 | @Test 55 | public void insertClientUserTest2(){ 56 | ClientUser user = new ClientUser(); 57 | user.setUsername("hellxz"); 58 | user.setPassword(passwordEncoder.encode("abc")); 59 | ClientUser save = clientUserRepositories.save(user); 60 | Assert.assertNotNull(save); 61 | Assert.assertEquals(user.getUsername(), save.getUsername()); 62 | Assert.assertEquals(user.getPassword(), save.getPassword()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-resource-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | authorization-code 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | authorization-code-resource-server 13 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-resource-server/src/main/java/com/github/hellxz/oauth2/AuthorizationCodeResourceServerApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * 资源服务器 入口 8 | * 9 | * @author hellxz 10 | */ 11 | @SpringBootApplication 12 | public class AuthorizationCodeResourceServerApp { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(AuthorizationCodeResourceServerApp.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-resource-server/src/main/java/com/github/hellxz/oauth2/config/ResourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.Primary; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.http.SessionCreationPolicy; 8 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 12 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 13 | import org.springframework.security.oauth2.provider.token.RemoteTokenServices; 14 | 15 | @Configuration 16 | @EnableResourceServer 17 | public class ResourceConfig extends ResourceServerConfigurerAdapter { 18 | 19 | @Bean 20 | public PasswordEncoder passwordEncoder() { 21 | return new BCryptPasswordEncoder(); 22 | } 23 | 24 | @Primary 25 | @Bean 26 | public RemoteTokenServices remoteTokenServices() { 27 | final RemoteTokenServices tokenServices = new RemoteTokenServices(); 28 | //设置授权服务器check_token端点完整地址 29 | tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token"); 30 | //设置客户端id与secret,注意:client_secret值不能使用passwordEncoder加密! 31 | tokenServices.setClientId("client-a"); 32 | tokenServices.setClientSecret("client-a-secret"); 33 | return tokenServices; 34 | } 35 | 36 | @Override 37 | public void configure(HttpSecurity http) throws Exception { 38 | //设置创建session策略 39 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); 40 | //@formatter:off 41 | //所有请求必须授权 42 | http.authorizeRequests() 43 | .anyRequest().authenticated(); 44 | //@formatter:on 45 | } 46 | 47 | @Override 48 | public void configure(ResourceServerSecurityConfigurer resources) { 49 | resources.resourceId("resource1").stateless(true); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-resource-server/src/main/java/com/github/hellxz/oauth2/web/controller/ResourceController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.controller; 2 | 3 | import com.github.hellxz.oauth2.web.vo.UserVO; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.PathVariable; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | public class ResourceController { 10 | 11 | @GetMapping("/user/{username}") 12 | public UserVO user(@PathVariable String username){ 13 | return new UserVO(username, username + "@foxmail.com"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-resource-server/src/main/java/com/github/hellxz/oauth2/web/vo/UserVO.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.vo; 2 | 3 | public class UserVO { 4 | private String username; 5 | private String email; 6 | 7 | public UserVO(String username, String email) { 8 | this.username = username; 9 | this.email = email; 10 | } 11 | 12 | public String getUsername() { 13 | return username; 14 | } 15 | 16 | public void setUsername(String username) { 17 | this.username = username; 18 | } 19 | 20 | public String getEmail() { 21 | return email; 22 | } 23 | 24 | public void setEmail(String email) { 25 | this.email = email; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /authorization-code/authorization-code-resource-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 -------------------------------------------------------------------------------- /authorization-code/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | spring-security-oauth2-learn 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | authorization-code 13 | pom 14 | 15 | authorization-code-authorization-server 16 | authorization-code-resource-server 17 | authorization-code-client-resttemplate-jdbc 18 | 19 | 20 | 21 | 22 | org.springframework.security.oauth 23 | spring-security-oauth2 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /client-credentials/README.md: -------------------------------------------------------------------------------- 1 | ## 客户端模式DEMO 2 | 以下是我的理解: 3 | 当用户发起一个访问资源服务的请求前,被客户端(浏览器)拦截到,它会先检查本地是否有token, 4 | 5 | 如果token不存在就先发起一次Post请求,用自己的客户端账号密码获取token, 6 | 7 | 然后使用此token添加到之前拦截到的请求头中,执行请求,返回资源 8 | 9 | **关键点在于:这里没有用户登录与授权的部分,实际相对授权服务器登录的是客户端** 10 | 11 | 1. 发起请求,登录授权服务器获取token 12 | ``` 13 | curl -X POST \ 14 | --user user-center:12345 http://localhost:8080/oauth/token \ 15 | -d "grant_type=client_credentials&scope=all" 16 | ``` 17 | 18 | 返回响应 19 | ```json 20 | { 21 | "access_token": "fc4721f4-c4a3-44f8-8232-a31cf59964ca", 22 | "token_type": "bearer", 23 | "expires_in": 43199, 24 | "scope": "all" 25 | } 26 | ``` 27 | 2. 调用资源接口 28 | ``` 29 | curl -X GET --user user-center:12345 http://localhost:8081/user/hellxz001 30 | -H 'Authorization: Bearer fc4721f4-c4a3-44f8-8232-a31cf59964ca' 31 | ``` 32 | 返回响应 33 | ```json 34 | { 35 | "username": "hellxz001", 36 | "email": "hellxz001@foxmail.com" 37 | } 38 | ``` 39 | 40 | ## 校验token 41 | 另外,我这边尝试了一下校验token的接口,之前使用授权码等校验时,只需要传token、client_id、client_secret 42 | 就可以正确校验token, 43 | 44 | 如果是client_credentials模式,校验接口时,需要使用client_id、client_secret登录,传参时只需要传token 45 | 46 | ``` 47 | curl -X POST --user user-center:12345 http://localhost:8080/oauth/check_token \ 48 | -d 'token=b462bd1f-a50c-4209-ac06-5a668143ed9e' 49 | ``` 50 | 返回结果 51 | ```json 52 | { 53 | "scope": [ 54 | "all" 55 | ], 56 | "active": true, 57 | "exp": 1574889562, 58 | "client_id": "user-center" 59 | } 60 | ``` -------------------------------------------------------------------------------- /client-credentials/client-credentials-authorization-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | client-credentials 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | client-credentials-authorization-server 13 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-authorization-server/src/main/java/com/github/hellxz/oauth2/ClientCredentialsAuthorizationApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ClientCredentialsAuthorizationApp { 8 | public static void main(String[] args) { 9 | SpringApplication.run(ClientCredentialsAuthorizationApp.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-authorization-server/src/main/java/com/github/hellxz/oauth2/config/AuthorizationConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 6 | import org.springframework.security.crypto.password.PasswordEncoder; 7 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 10 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 11 | 12 | @Configuration 13 | @EnableAuthorizationServer 14 | public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { 15 | @Bean 16 | public PasswordEncoder passwordEncoder(){ 17 | return new BCryptPasswordEncoder(); 18 | } 19 | 20 | @Override 21 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 22 | //@formatter:off 23 | clients.inMemory() 24 | .withClient("user-center") 25 | .secret(passwordEncoder().encode("12345")) 26 | .authorizedGrantTypes("client_credentials") 27 | .scopes("all"); 28 | //@formatter:on 29 | } 30 | 31 | @Override 32 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 33 | security.allowFormAuthenticationForClients() 34 | .checkTokenAccess("isAuthenticated()"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-authorization-server/src/main/java/com/github/hellxz/oauth2/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 | 8 | @Configuration 9 | @EnableWebSecurity 10 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 11 | 12 | @Override 13 | protected void configure(HttpSecurity http) throws Exception { 14 | http.authorizeRequests().anyRequest().authenticated(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-authorization-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | client-credentials 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | client-credentials-client 13 | 14 | 15 | 16 | org.springframework.cloud 17 | spring-cloud-starter-openfeign 18 | 19 | 20 | commons-io 21 | commons-io 22 | 23 | 24 | org.apache.commons 25 | commons-lang3 26 | 27 | 28 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/ClientCredentialsClientApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | 7 | /** 8 | * 使用feign使用ok-http调用接口,测试拦截feign请求,获取token放置到请求头上 9 | */ 10 | @SpringBootApplication 11 | @EnableFeignClients 12 | public class ClientCredentialsClientApp { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ClientCredentialsClientApp.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/config/SecureConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 | 8 | @Configuration 9 | @EnableWebSecurity 10 | public class SecureConfig extends WebSecurityConfigurerAdapter { 11 | @Override 12 | protected void configure(HttpSecurity http) throws Exception { 13 | //因为父工程依赖了spring security, 这里不做拦截 14 | http.authorizeRequests().antMatchers("/**").permitAll(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/config/UaaProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | @ConfigurationProperties(prefix = "uaa") 8 | public class UaaProperties { 9 | private String clientId; 10 | private String clientSecret; 11 | private String tokenEndpoint; 12 | 13 | public String getClientId() { 14 | return clientId; 15 | } 16 | 17 | public void setClientId(String clientId) { 18 | this.clientId = clientId; 19 | } 20 | 21 | public String getClientSecret() { 22 | return clientSecret; 23 | } 24 | 25 | public void setClientSecret(String clientSecret) { 26 | this.clientSecret = clientSecret; 27 | } 28 | 29 | public String getTokenEndpoint() { 30 | return tokenEndpoint; 31 | } 32 | 33 | public void setTokenEndpoint(String tokenEndpoint) { 34 | this.tokenEndpoint = tokenEndpoint; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/dto/UserDto.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.dto; 2 | 3 | import org.apache.commons.lang3.builder.ToStringBuilder; 4 | 5 | public class UserDto { 6 | private String username; 7 | private String email; 8 | 9 | public UserDto(String username, String email) { 10 | this.username = username; 11 | this.email = email; 12 | } 13 | 14 | public String getUsername() { 15 | return username; 16 | } 17 | 18 | public void setUsername(String username) { 19 | this.username = username; 20 | } 21 | 22 | public String getEmail() { 23 | return email; 24 | } 25 | 26 | public void setEmail(String email) { 27 | this.email = email; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return ToStringBuilder.reflectionToString(this); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/feign/UserFeignClient.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.feign; 2 | 3 | import com.github.hellxz.oauth2.dto.UserDto; 4 | import com.github.hellxz.oauth2.feign.fallback.UserFeignClientFallback; 5 | import org.springframework.cloud.openfeign.FeignClient; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | 9 | @FeignClient(name = "user-feign",url = "http://localhost:8081", fallback = UserFeignClientFallback.class) 10 | public interface UserFeignClient { 11 | 12 | @GetMapping("/user/{username}") 13 | UserDto getUser(@PathVariable("username") String username); 14 | } 15 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/feign/fallback/UserFeignClientFallback.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.feign.fallback; 2 | 3 | import com.github.hellxz.oauth2.dto.UserDto; 4 | import com.github.hellxz.oauth2.feign.UserFeignClient; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class UserFeignClientFallback implements UserFeignClient { 9 | @Override 10 | public UserDto getUser(String username) { 11 | System.err.println("调用接口失败"); 12 | return null; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/filter/FeignTokenInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.filter; 2 | 3 | import com.github.hellxz.oauth2.config.UaaProperties; 4 | import com.github.hellxz.oauth2.utils.TokenUtils; 5 | import feign.RequestInterceptor; 6 | import feign.RequestTemplate; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.util.CollectionUtils; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.*; 13 | 14 | /** 15 | * Feign拦截器,为请求头上加上token 16 | */ 17 | @Configuration 18 | public class FeignTokenInterceptor implements RequestInterceptor { 19 | 20 | @Resource 21 | private UaaProperties uaaProperties; 22 | 23 | @Resource 24 | private TokenUtils tokenUtils; 25 | 26 | /** 27 | * 请求头中没有Authorization的,调用资源服务器获取token置于请求头,使请求可被访问 28 | * 使用客户端模式 29 | */ 30 | @Override 31 | public void apply(RequestTemplate requestTemplate) { 32 | Map> headers = requestTemplate.headers(); 33 | if (CollectionUtils.isEmpty(headers) || !headers.containsKey("Authorization")) { 34 | String clientId = uaaProperties.getClientId(); 35 | String clientSecret = uaaProperties.getClientSecret(); 36 | String tokenEndpoint = uaaProperties.getTokenEndpoint(); 37 | String bearerToken = tokenUtils.getBearerTokenByClientCredentials(clientId, clientSecret, tokenEndpoint); 38 | if (StringUtils.isNotBlank(bearerToken)) { 39 | requestTemplate.header("Authorization", bearerToken); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/utils/TokenUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.utils; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import org.apache.commons.lang3.builder.ToStringBuilder; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.http.HttpHeaders; 7 | import org.springframework.http.HttpMethod; 8 | import org.springframework.http.RequestEntity; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.util.LinkedMultiValueMap; 12 | import org.springframework.util.MultiValueMap; 13 | import org.springframework.web.client.RestTemplate; 14 | 15 | import javax.annotation.Resource; 16 | import java.net.URI; 17 | import java.util.Objects; 18 | 19 | @Component 20 | public class TokenUtils { 21 | 22 | @Resource(name = "tokenTemplate") 23 | private RestTemplate tokenTemplate; 24 | 25 | public String getBearerTokenByClientCredentials(String clientId, String clientSecret, String tokenEndpoint){ 26 | HttpHeaders httpHeaders = new HttpHeaders(); 27 | httpHeaders.setBasicAuth(clientId, clientSecret); 28 | MultiValueMap params = new LinkedMultiValueMap<>(); 29 | params.add("grant_type", "client_credentials"); 30 | RequestEntity> requestEntity 31 | = new RequestEntity<>(params, httpHeaders, HttpMethod.POST, URI.create(tokenEndpoint)); 32 | ResponseEntity exchange = tokenTemplate.exchange(requestEntity, TokenDTO.class); 33 | if (exchange.getStatusCode().is2xxSuccessful()) { 34 | return "Bearer " + Objects.requireNonNull(exchange.getBody()).getAccessToken(); 35 | }else{ 36 | return ""; 37 | } 38 | } 39 | 40 | static class TokenDTO { 41 | @JsonProperty("access_token") 42 | private String accessToken; 43 | @JsonProperty("refresh_token") 44 | private String refreshToken; 45 | @JsonProperty("token_type") 46 | private String tokenType; 47 | @JsonProperty("expires_in") 48 | private String expiresIn; 49 | @JsonProperty("scope") 50 | private String scope; 51 | 52 | public String getRefreshToken() { 53 | return refreshToken; 54 | } 55 | 56 | public void setRefreshToken(String refreshToken) { 57 | this.refreshToken = refreshToken; 58 | } 59 | 60 | public String getAccessToken() { 61 | return accessToken; 62 | } 63 | 64 | public void setAccessToken(String accessToken) { 65 | this.accessToken = accessToken; 66 | } 67 | 68 | public String getTokenType() { 69 | return tokenType; 70 | } 71 | 72 | public void setTokenType(String tokenType) { 73 | this.tokenType = tokenType; 74 | } 75 | 76 | public String getExpiresIn() { 77 | return expiresIn; 78 | } 79 | 80 | public void setExpiresIn(String expiresIn) { 81 | this.expiresIn = expiresIn; 82 | } 83 | 84 | public String getScope() { 85 | return scope; 86 | } 87 | 88 | public void setScope(String scope) { 89 | this.scope = scope; 90 | } 91 | 92 | @Override 93 | public String toString() { 94 | return ToStringBuilder.reflectionToString(this); 95 | } 96 | } 97 | 98 | @Bean("tokenTemplate") 99 | public RestTemplate tokenTemplate(){ 100 | return new RestTemplate(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/java/com/github/hellxz/oauth2/web/UserController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web; 2 | 3 | import com.github.hellxz.oauth2.dto.UserDto; 4 | import com.github.hellxz.oauth2.feign.UserFeignClient; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import javax.annotation.Resource; 9 | 10 | /** 11 | * 测试调用用户资源服务器的controller,用于测试 12 | */ 13 | @RestController 14 | public class UserController { 15 | 16 | @Resource 17 | UserFeignClient userClient; 18 | 19 | @GetMapping("/user") 20 | public UserDto getResourceUser(){ 21 | return userClient.getUser("test"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-client/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9001 3 | feign: 4 | okhttp: 5 | enabled: true 6 | uaa: 7 | clientId: user-center 8 | clientSecret: 12345 9 | tokenEndpoint: http://localhost:8080/oauth/token 10 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-resource-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | client-credentials 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | client-credentials-resource-server 13 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-resource-server/src/main/java/com/github/hellxz/oauth2/ClientCredentialsResourceServerApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ClientCredentialsResourceServerApp { 8 | public static void main(String[] args) { 9 | SpringApplication.run(ClientCredentialsResourceServerApp.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-resource-server/src/main/java/com/github/hellxz/oauth2/config/ResourceServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.http.SessionCreationPolicy; 7 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 9 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 10 | import org.springframework.security.oauth2.provider.token.RemoteTokenServices; 11 | 12 | @Configuration 13 | @EnableResourceServer 14 | public class ResourceServerConfig extends ResourceServerConfigurerAdapter { 15 | 16 | @Bean 17 | public RemoteTokenServices remoteTokenServices(){ 18 | final RemoteTokenServices remoteTokenServices = new RemoteTokenServices(); 19 | remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token"); 20 | remoteTokenServices.setClientId("user-center"); 21 | remoteTokenServices.setClientSecret("12345"); 22 | return remoteTokenServices; 23 | } 24 | 25 | @Override 26 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 27 | resources.stateless(true); 28 | } 29 | 30 | @Override 31 | public void configure(HttpSecurity http) throws Exception { 32 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); 33 | http.authorizeRequests().anyRequest().authenticated(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-resource-server/src/main/java/com/github/hellxz/oauth2/web/controller/ResourceController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.controller; 2 | 3 | import com.github.hellxz.oauth2.web.vo.UserVO; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.PathVariable; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | public class ResourceController { 10 | 11 | @GetMapping("/user/{username}") 12 | public UserVO user(@PathVariable String username){ 13 | return new UserVO(username, username + "@foxmail.com"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-resource-server/src/main/java/com/github/hellxz/oauth2/web/vo/UserVO.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.vo; 2 | 3 | public class UserVO { 4 | private String username; 5 | private String email; 6 | 7 | public UserVO(String username, String email) { 8 | this.username = username; 9 | this.email = email; 10 | } 11 | 12 | public String getUsername() { 13 | return username; 14 | } 15 | 16 | public void setUsername(String username) { 17 | this.username = username; 18 | } 19 | 20 | public String getEmail() { 21 | return email; 22 | } 23 | 24 | public void setEmail(String email) { 25 | this.email = email; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client-credentials/client-credentials-resource-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 -------------------------------------------------------------------------------- /client-credentials/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | spring-security-oauth2-learn 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | client-credentials 13 | pom 14 | 15 | client-credentials-authorization-server 16 | client-credentials-resource-server 17 | client-credentials-client 18 | 19 | 20 | 21 | 22 | org.springframework.security.oauth 23 | spring-security-oauth2 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /implicit/README.md: -------------------------------------------------------------------------------- 1 | ## 简化模式(隐式授权模式)Demo 2 | 1. 客户端拼url重定向,用户登录并授权 3 | GET请求 4 | ``` 5 | http://localhost:8080/oauth/authorize?client_id=client-a&redirect_uri=http://localhost:9001/callback&response_type=token&scope=read_user_info 6 | ``` 7 | 请求参数列表: 8 | - client_id=客户端id 9 | - redirect_uri=回调url 一定要与授权服务器配置保持一致,否则得不到授权码 10 | - response_type=token 简化模式必须是token 11 | - scope=作用域 与授权服务器配置保持一致 12 | - state=自定义串(可选) 13 | 14 | 15 | > `state`这个字段可选填,在生产环境下可以传加密串用来验证授权回调请求可信 16 | > 注意: 简化模式(隐式授权模式)不需要client_secret > 17 | > 18 | 19 | 2. 授权服务器返回token 20 | ``` 21 | http://localhost:9001/callback#access_token=d87e1391-78a3-476f-afda-752e5884a93a&token_type=bearer&expires_in=119 22 | ``` 23 | 3. 客户端保存token,并在请求时带上此token 24 | ``` 25 | curl -X GET \ 26 | http://localhost:8081/user/hellxz001 \ 27 | -H 'Authorization: Bearer 0b68fd19-15a5-488e-bc80-dd918cd23cf8' \ 28 | ``` 29 | 响应结果 30 | ```json 31 | { 32 | "username": "hellxz001", 33 | "email": "hellxz001@foxmail.com" 34 | } 35 | ``` 36 | 37 | ## 简化模式流程梳理 38 | 1. 用户请求访问资源服务器资源,客户端(浏览器端)发现本地没有缓存用户授权token 39 | 2. 客户端拼url重定向到授权服务器请求页面 40 | 3. 用户登录,授权 41 | 4. 授权成功后,回调url返回token给客户端 42 | 5. 客户端收到token后,保存token并在请求时带上token,访问资源 43 | -------------------------------------------------------------------------------- /implicit/implicit-authorization-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | implicit 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | implicit-authorization-server 13 | -------------------------------------------------------------------------------- /implicit/implicit-authorization-server/src/main/java/com/github/hellxz/oauth2/ImplicitAuthorizationServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImplicitAuthorizationServerApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(ImplicitAuthorizationServerApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /implicit/implicit-authorization-server/src/main/java/com/github/hellxz/oauth2/config/AuthorizationConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.crypto.password.PasswordEncoder; 6 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 7 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 10 | 11 | //授权服务器配置 12 | @Configuration 13 | @EnableAuthorizationServer //开启授权服务 14 | public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { 15 | 16 | @Autowired 17 | private PasswordEncoder passwordEncoder; 18 | 19 | @Override 20 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 21 | //允许表单提交 22 | security.allowFormAuthenticationForClients() 23 | .checkTokenAccess("permitAll()"); //参数与security访问控制一致 24 | } 25 | 26 | @Override 27 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 28 | // @formatter: off 29 | clients.inMemory() 30 | .withClient("client-a") //client端唯一标识 31 | .authorizedGrantTypes("implicit") //授权模式标识 32 | .accessTokenValiditySeconds(120) //访问令牌的有效期,这里设置120s 33 | .scopes("read_user_info") //作用域 34 | .resourceIds("resource1") //资源id 35 | .redirectUris("http://localhost:9001/callback") //回调地址 36 | .and() 37 | .withClient("resource-server") //资源服务器校验token时用的客户端信息,仅需要client_id与密码 38 | .secret(passwordEncoder.encode("test")); 39 | // @formatter: on 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /implicit/implicit-authorization-server/src/main/java/com/github/hellxz/oauth2/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 10 | import org.springframework.security.crypto.password.PasswordEncoder; 11 | 12 | import java.util.Collections; 13 | 14 | @Configuration 15 | @EnableWebSecurity 16 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 17 | 18 | @Bean 19 | public PasswordEncoder passwordEncoder(){ 20 | return new BCryptPasswordEncoder(); 21 | } 22 | 23 | @Override 24 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 25 | // @formatter: off 26 | auth.inMemoryAuthentication() 27 | .withUser("hellxz") 28 | .password(passwordEncoder().encode("xyz")) 29 | .authorities(Collections.emptyList()); 30 | // @formatter: on 31 | } 32 | 33 | @Override 34 | protected void configure(HttpSecurity http) throws Exception { 35 | http.authorizeRequests() 36 | .anyRequest().authenticated() //所有请求都需要通过认证 37 | .and() 38 | .httpBasic() //Basic提交 39 | .and() 40 | .csrf().disable(); //关跨域保护 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /implicit/implicit-authorization-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 -------------------------------------------------------------------------------- /implicit/implicit-resource-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | implicit 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | implicit-resource-server 13 | -------------------------------------------------------------------------------- /implicit/implicit-resource-server/src/main/java/com/github/hellxz/oauth2/ImplicitResourceServerApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * 授权服务器 入口 8 | * 9 | * @author hellxz 10 | */ 11 | @SpringBootApplication 12 | public class ImplicitResourceServerApp { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ImplicitResourceServerApp.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /implicit/implicit-resource-server/src/main/java/com/github/hellxz/oauth2/config/ResourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.Primary; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.http.SessionCreationPolicy; 8 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 12 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 13 | import org.springframework.security.oauth2.provider.token.RemoteTokenServices; 14 | 15 | @Configuration 16 | @EnableResourceServer 17 | public class ResourceConfig extends ResourceServerConfigurerAdapter { 18 | 19 | @Bean 20 | public PasswordEncoder passwordEncoder() { 21 | return new BCryptPasswordEncoder(); 22 | } 23 | 24 | @Primary 25 | @Bean 26 | public RemoteTokenServices remoteTokenServices() { 27 | final RemoteTokenServices tokenServices = new RemoteTokenServices(); 28 | tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token"); 29 | //这里的clientId和secret对应资源服务器信息,授权服务器处需要配置 30 | tokenServices.setClientId("resource-server"); 31 | tokenServices.setClientSecret("test"); 32 | return tokenServices; 33 | } 34 | 35 | @Override 36 | public void configure(HttpSecurity http) throws Exception { 37 | //设置创建session策略 38 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); 39 | //@formatter:off 40 | //所有请求必须授权 41 | http.authorizeRequests() 42 | .anyRequest().authenticated(); 43 | //@formatter:on 44 | } 45 | 46 | @Override 47 | public void configure(ResourceServerSecurityConfigurer resources) { 48 | resources.resourceId("resource1").stateless(true); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /implicit/implicit-resource-server/src/main/java/com/github/hellxz/oauth2/web/controller/ResourceController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.controller; 2 | 3 | import com.github.hellxz.oauth2.web.vo.UserVO; 4 | import org.springframework.security.core.context.SecurityContextHolder; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | @RestController 10 | public class ResourceController { 11 | 12 | @GetMapping("/user/{username}") 13 | public UserVO user(@PathVariable String username){ 14 | System.err.println(SecurityContextHolder.getContext().getAuthentication()); 15 | return new UserVO(username, username + "@foxmail.com"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /implicit/implicit-resource-server/src/main/java/com/github/hellxz/oauth2/web/vo/UserVO.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.vo; 2 | 3 | public class UserVO { 4 | private String username; 5 | private String email; 6 | 7 | public UserVO(String username, String email) { 8 | this.username = username; 9 | this.email = email; 10 | } 11 | 12 | public String getUsername() { 13 | return username; 14 | } 15 | 16 | public void setUsername(String username) { 17 | this.username = username; 18 | } 19 | 20 | public String getEmail() { 21 | return email; 22 | } 23 | 24 | public void setEmail(String email) { 25 | this.email = email; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /implicit/implicit-resource-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 -------------------------------------------------------------------------------- /implicit/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | spring-security-oauth2-learn 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | implicit 13 | pom 14 | 15 | implicit-authorization-server 16 | implicit-resource-server 17 | 18 | 19 | 20 | 21 | org.springframework.security.oauth 22 | spring-security-oauth2 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /jwt/README.md: -------------------------------------------------------------------------------- 1 | # JWT 2 | 这部分demo并非是OAuth2授权模式之一,是使用JWT作为token的演示代码 3 | 4 | ## JWT概念 5 | JWT是一种自包含的加密token,整体分为三部分: 6 | - Header : 标头通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,例如HMAC SHA256或RSA。标头通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,例如HMAC SHA256或RSA。 7 | - Payload : 令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户)和其他数据的声明。共有三种类型的claims:registered, public, and private claims.。 8 | - Signature : 要创建签名部分,您必须获取编码的Header,编码的有效Payload,密钥,标头中指定的算法,并对其进行签名。 9 | ### JWT结构 10 | > 每个json块使用Base64加密,然后使用`.`连接在一起 11 | 12 | 其结构为`Header.Payload.Signature` 13 | 14 | e.g. 15 | 16 | ![](https://github.com/hellxz/spring-security-oauth2-learn/blob/master/pictures/encoded-jwt3.png) 17 | 18 | ### Header 19 | Header这部分包含令牌所用的算法(alg:algorithm, 常用的有HMAC SHA256或RSA)和 令牌的类型(typ: Token Type,即JWT) 20 | 未被加密前的样子就像 21 | ```json 22 | { 23 | "alg": "HS256", 24 | "typ": "JWT" 25 | } 26 | ``` 27 | Header部分使用Base64Url进行加密 28 | ### Payload 29 | Payload这部分包含token的信息,这部分可以包含 已被注册信息、公有的信息、私有的信息,提供了很多可以自定义的部分 30 | 官方给了一些推荐使用的已定义的参数名(已被注册信息): 31 | - "iss" (Issuer) Claim 32 | - "sub" (Subject) Claim 33 | - "aud" (Audience) Claim 34 | - "exp" (Expiration Time) Claim 35 | - "nbf" (Not Before) Claim 36 | - "iat" (Issued At) Claim 37 | - "jti" (JWT ID) Claim 38 | 公有的信息、私有的信息都是自定义的,注意不要与官方给的冲突即可,另外注意保持参数尽量少且不要暴露隐私数据 39 | 40 | Payload部分使用Base64Url进行加密 41 | ### Signature 42 | 签名部分使用Header中定义的算法与密钥,把经过Base64Url加密的`Header.Payload`进行加密,得出签名。用来验证此token是授权服务器颁发的,而不是伪造的 43 | 44 | demo中使用的是对称密钥加密 45 | 46 | ## 使用方式 47 | 与普通的token使用一样,在请求头中添加`Authorization:Bearer 你的token` 48 | 49 | ## 使用JWT的好处 50 | 不使用session保持会话,实现无状态服务,避免大量session对服务器的资源使用,从而容易扩展,对于分布式和微服务应用特别多 51 | 52 | 另外,一般来说,JWT是自包含的token,使用它授权服务器就只需要颁发一次token,资源服务器可以通过这个token直接解析出用户信息,同时也可以减少授权服务器的请求次数 53 | 54 | ## 使用JWT的缺点 55 | 缺点就是JWT的token没有立即revoke(收回)权限的功能,只能等待token过期 56 | 57 | 所以,使用JWT时,请尽量设置较短的过期时间,保证服务安全 -------------------------------------------------------------------------------- /jwt/jwt-authorization-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | jwt 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | jwt-authorization-server 13 | -------------------------------------------------------------------------------- /jwt/jwt-authorization-server/src/main/java/com/github/hellxz/oauth2/JwtAuthorizationServerApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * 授权服务器 入口 8 | * 9 | * @author hellxz 10 | */ 11 | @SpringBootApplication 12 | public class JwtAuthorizationServerApp { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(JwtAuthorizationServerApp.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jwt/jwt-authorization-server/src/main/java/com/github/hellxz/oauth2/config/AuthorizationConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.core.io.ClassPathResource; 7 | import org.springframework.security.authentication.AuthenticationManager; 8 | import org.springframework.security.core.userdetails.UserDetailsService; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 12 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 13 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 14 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 15 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 16 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 17 | import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory; 18 | 19 | //授权服务器配置 20 | @Configuration 21 | @EnableAuthorizationServer //开启授权服务 22 | public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { 23 | 24 | @Autowired 25 | private AuthenticationManager authenticationManager; 26 | 27 | @Autowired 28 | public UserDetailsService userDetailsService; 29 | 30 | @Autowired 31 | private PasswordEncoder passwordEncoder; 32 | 33 | @Override 34 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 35 | //允许表单提交 36 | security.allowFormAuthenticationForClients() 37 | .checkTokenAccess("permitAll()") //这里这两个配置只是用来测试使用,生产环境可以关闭,jwt不需要再去授权服务器校验token 38 | .tokenKeyAccess("permitAll()"); 39 | } 40 | 41 | @Override 42 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 43 | // @formatter: off 44 | clients.inMemory() 45 | .withClient("client-a") //client端唯一标识 46 | .secret(passwordEncoder.encode("client-a-secret")) //client-a的密码,这里的密码应该是加密后的 47 | .authorizedGrantTypes("client_credentials","password", "refresh_token") //授权模式标识,开启刷新token功能 48 | .scopes("read_user_info", "service", "users") //作用域 49 | .resourceIds("resource1") //资源id,如不需限制资源id,注释此处即可 50 | .redirectUris("http://localhost:9001/callback"); //回调地址 51 | 52 | // @formatter: on 53 | } 54 | 55 | @Override 56 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 57 | endpoints.authenticationManager(authenticationManager) 58 | .userDetailsService(userDetailsService) 59 | .tokenStore(jwtTokenStore()) 60 | .accessTokenConverter(jwtAccessTokenConverter()); 61 | } 62 | 63 | /** 64 | * jwt访问token转换器 65 | */ 66 | @Bean 67 | public JwtAccessTokenConverter jwtAccessTokenConverter(){ 68 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 69 | // converter.setSigningKey("my-sign-key"); //密钥,默认是HMACSHA256对称加密 70 | KeyStoreKeyFactory storeKeyFactory = new KeyStoreKeyFactory( 71 | new ClassPathResource("hellxz-jwt.jks"), "hellxzTest".toCharArray()); 72 | converter.setKeyPair(storeKeyFactory.getKeyPair("hellxz-jwt")); 73 | return converter; 74 | } 75 | 76 | /** 77 | * jwt的token存储对象 78 | */ 79 | @Bean 80 | public JwtTokenStore jwtTokenStore(){ 81 | return new JwtTokenStore(jwtAccessTokenConverter()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /jwt/jwt-authorization-server/src/main/java/com/github/hellxz/oauth2/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.authentication.AuthenticationManager; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.core.userdetails.User; 12 | import org.springframework.security.core.userdetails.UserDetails; 13 | import org.springframework.security.core.userdetails.UserDetailsService; 14 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 15 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 16 | import org.springframework.security.crypto.password.PasswordEncoder; 17 | import org.springframework.util.StringUtils; 18 | 19 | import java.util.Collections; 20 | 21 | /** 22 | * 这里记个坑: 23 | * 1. 重写了configure(AuthenticationManagerBuilder auth)方法提供登录用户信息时,无需再在AuthenticationManager和UserDetailsService中再写一遍查用户信息的操作 24 | * 2. 声明bean为UserDetailsService不要使用super.userDetailsServiceBean(),当刷新token时会造成StackOverFlow,转而使用super.userDetailsService()便好 25 | */ 26 | @Configuration 27 | @EnableWebSecurity 28 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 29 | 30 | @Bean 31 | public AuthenticationManager authenticationManager() throws Exception { 32 | return super.authenticationManager(); 33 | } 34 | 35 | @Bean 36 | public UserDetailsService userDetailsService(){ 37 | return super.userDetailsService(); 38 | } 39 | 40 | @Bean 41 | public PasswordEncoder passwordEncoder(){ 42 | return new BCryptPasswordEncoder(); 43 | } 44 | 45 | @Override 46 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 47 | // @formatter: off 48 | auth.inMemoryAuthentication() 49 | .withUser("hellxz") 50 | .password(passwordEncoder().encode("xyz")) 51 | .authorities(Collections.emptyList()); 52 | // @formatter: on 53 | } 54 | 55 | @Override 56 | protected void configure(HttpSecurity http) throws Exception { 57 | http.authorizeRequests() 58 | .anyRequest().authenticated() //所有请求都需要通过认证 59 | .and() 60 | .httpBasic() //Basic提交 61 | .and() 62 | .csrf().disable(); //关跨域保护 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /jwt/jwt-authorization-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 -------------------------------------------------------------------------------- /jwt/jwt-authorization-server/src/main/resources/hellxz-jwt.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellxz/spring-security-oauth2-learn/f8c9843f70108fab99e888da8acd780ccace1818/jwt/jwt-authorization-server/src/main/resources/hellxz-jwt.jks -------------------------------------------------------------------------------- /jwt/jwt-resource-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | jwt 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | jwt-resource-server 13 | 14 | -------------------------------------------------------------------------------- /jwt/jwt-resource-server/src/main/java/com/github/hellxz/oauth2/JwtResourceServerApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * 授权服务器 入口 8 | * 9 | * @author hellxz 10 | */ 11 | @SpringBootApplication 12 | public class JwtResourceServerApp { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(JwtResourceServerApp.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jwt/jwt-resource-server/src/main/java/com/github/hellxz/oauth2/config/ResourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.Primary; 6 | import org.springframework.core.io.ClassPathResource; 7 | import org.springframework.core.io.Resource; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.http.SessionCreationPolicy; 10 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 11 | import org.springframework.security.crypto.password.PasswordEncoder; 12 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 13 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 14 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 15 | import org.springframework.security.oauth2.provider.token.RemoteTokenServices; 16 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 17 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 18 | import org.springframework.util.FileCopyUtils; 19 | 20 | import java.io.IOException; 21 | 22 | @Configuration 23 | @EnableResourceServer 24 | public class ResourceConfig extends ResourceServerConfigurerAdapter { 25 | 26 | @Bean 27 | public PasswordEncoder passwordEncoder() { 28 | return new BCryptPasswordEncoder(); 29 | } 30 | 31 | // /** 32 | // * 这里使用的是调用授权服务器接口进行校验token的,除了这种方式,如果授权服务器将token保存在某些存储器中,可以使用访问存储器来实现 33 | // */ 34 | // @Primary 35 | // @Bean 36 | // public RemoteTokenServices remoteTokenServices() { 37 | // final RemoteTokenServices tokenServices = new RemoteTokenServices(); 38 | // tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token"); 39 | // tokenServices.setClientId("client-a"); 40 | // tokenServices.setClientSecret("client-a-secret"); 41 | // return tokenServices; 42 | // } 43 | 44 | @Override 45 | public void configure(HttpSecurity http) throws Exception { 46 | //设置创建session策略 47 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); 48 | //@formatter:off 49 | //所有请求必须授权 50 | http.authorizeRequests() 51 | .anyRequest().authenticated(); 52 | //@formatter:on 53 | } 54 | 55 | @Override 56 | public void configure(ResourceServerSecurityConfigurer resources) { 57 | //@formatter:off 58 | //如不需要限制资源id,请在授权配置处去除resourceIds的配置 59 | resources.resourceId("resource1") 60 | .tokenStore(jwtTokenStore()); 61 | //@formatter:on 62 | } 63 | 64 | /** 65 | * jwt访问token转换器 66 | */ 67 | @Bean 68 | public JwtAccessTokenConverter jwtAccessTokenConverter(){ 69 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 70 | // converter.setSigningKey("my-sign-key"); //对称加密算法使用与授权服务器相同的signingKey 71 | Resource resource = new ClassPathResource("public.cert"); 72 | String publicKey; 73 | try { 74 | publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream())); 75 | } catch (IOException e) { 76 | throw new RuntimeException(e); 77 | } 78 | converter.setVerifierKey(publicKey); 79 | return converter; 80 | } 81 | 82 | /** 83 | * jwt的token存储对象 84 | */ 85 | @Bean 86 | public JwtTokenStore jwtTokenStore(){ 87 | return new JwtTokenStore(jwtAccessTokenConverter()); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /jwt/jwt-resource-server/src/main/java/com/github/hellxz/oauth2/web/controller/ResourceController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.controller; 2 | 3 | import com.github.hellxz.oauth2.web.vo.UserVO; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.security.core.context.SecurityContext; 7 | import org.springframework.security.core.context.SecurityContextHolder; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | public class ResourceController { 14 | private static final Logger log = LoggerFactory.getLogger(ResourceController.class); 15 | 16 | @GetMapping("/user/{username}") 17 | public UserVO user(@PathVariable String username){ 18 | log.info("{}", SecurityContextHolder.getContext().getAuthentication()); 19 | return new UserVO(username, username + "@foxmail.com"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jwt/jwt-resource-server/src/main/java/com/github/hellxz/oauth2/web/vo/UserVO.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.vo; 2 | 3 | public class UserVO { 4 | private String username; 5 | private String email; 6 | 7 | public UserVO(String username, String email) { 8 | this.username = username; 9 | this.email = email; 10 | } 11 | 12 | public String getUsername() { 13 | return username; 14 | } 15 | 16 | public void setUsername(String username) { 17 | this.username = username; 18 | } 19 | 20 | public String getEmail() { 21 | return email; 22 | } 23 | 24 | public void setEmail(String email) { 25 | this.email = email; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jwt/jwt-resource-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 -------------------------------------------------------------------------------- /jwt/jwt-resource-server/src/main/resources/public.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU7zulFUVBXmZD28xwM4 3 | ul5e9yFrToLgWKHlNLlp904/GbiWBoZ4tcBcNq3VxLGBN9VOqfP1P5C7fRgz95UI 4 | 7ShKCKgsFFGL2rAqsplMDClN/adfsxmpF06rVIkGgce9tR0Q0iONcaN+b/lArK4T 5 | Au76QsQwn9MLXlznVfczclZOZSfDNju+1JuBzqt6fEPWqalBUVYdV0zCUDG8ikN1 6 | l9D0m1tSSaKpiTrU2yEUGUji+79Ury7Y8BClEX6d4CTl9TQAhL5g32GoJEc0S2y+ 7 | 0bqeqUsv1nUt9KiJT9kiOvA+Q7o2T8OHuqQT9le7kvmIi4gSX5vSNvvZagE2Uglh 8 | zQIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /jwt/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | spring-security-oauth2-learn 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | jwt 13 | pom 14 | 15 | 16 | jwt-authorization-server 17 | jwt-resource-server 18 | 19 | 20 | 21 | 22 | org.springframework.security.oauth 23 | spring-security-oauth2 24 | 25 | 26 | org.springframework.security 27 | spring-security-jwt 28 | 29 | 30 | -------------------------------------------------------------------------------- /password/README.md: -------------------------------------------------------------------------------- 1 | ## 密码模式Demo 2 | 密码模式用户与其它几个模式相比,更加简单一些,用户访问资源时,客户端(浏览器)跳转自己的登录页面, 3 | 用户输入账号密码提交表单,表单提交时带上客户端的账号和密码+用户账户密码+scope+grant_type 4 | 授权服务器校验通过后直接返回token 5 | > 这里要注意:表单提交的uri是`/oauth/token` 6 | 7 | 1. 带上客户端账号密码与用户账户密码获取token 8 | ``` 9 | curl -X POST --user client-a:client-a-secret http://localhost:8080/oauth/token -H "accept: application/json" -H "content-type: application/x-www-form-urlencoded" -d "grant_type=password&username=hellxz&password=xyz&scope=read_scope" 10 | ``` 11 | 返回token 12 | ```json 13 | { 14 | "access_token": "58d25f8c-ea0e-40e0-9b55-9d7ef25c8145", 15 | "token_type": "bearer", 16 | "expires_in": 43199, 17 | "scope": "read_scope" 18 | } 19 | ``` 20 | 2. 使用token访问资源 21 | ``` 22 | curl -X GET \ 23 | http://localhost:8081/user/hellxz001 \ 24 | -H 'Authorization: Bearer 58d25f8c-ea0e-40e0-9b55-9d7ef25c8145' \ 25 | ``` 26 | 返回响应 27 | ```json 28 | { 29 | "username": "hellxz001", 30 | "email": "hellxz001@foxmail.com" 31 | } 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /password/password-authorization-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | password 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | password-authorization-server 13 | 14 | 15 | -------------------------------------------------------------------------------- /password/password-authorization-server/src/main/java/com/github/hellxz/oauth2/PasswordAuthorizationApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PasswordAuthorizationApp { 8 | public static void main(String[] args) { 9 | SpringApplication.run(PasswordAuthorizationApp.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /password/password-authorization-server/src/main/java/com/github/hellxz/oauth2/config/AuthorizationConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.authentication.AuthenticationManager; 6 | import org.springframework.security.crypto.password.PasswordEncoder; 7 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 10 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 11 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 12 | 13 | @Configuration 14 | @EnableAuthorizationServer 15 | public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { 16 | 17 | @Autowired 18 | private AuthenticationManager authenticationManager; 19 | 20 | @Autowired 21 | public PasswordEncoder passwordEncoder; 22 | 23 | //配置客户端 24 | @Override 25 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 26 | //@formatter:off 27 | clients.inMemory() 28 | .withClient("client-a") 29 | .secret(passwordEncoder.encode("client-a-secret")) 30 | .authorizedGrantTypes("password") 31 | .scopes("read_scope"); 32 | //@formatter:on 33 | } 34 | 35 | @Override 36 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 37 | endpoints.authenticationManager(authenticationManager); 38 | } 39 | 40 | @Override 41 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 42 | security.allowFormAuthenticationForClients() 43 | .checkTokenAccess("isAuthenticated()"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /password/password-authorization-server/src/main/java/com/github/hellxz/oauth2/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.authentication.AuthenticationManager; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 | import org.springframework.security.crypto.password.PasswordEncoder; 14 | import org.springframework.util.StringUtils; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Collections; 18 | 19 | @Configuration 20 | @EnableWebSecurity 21 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 22 | 23 | @Bean 24 | public PasswordEncoder passwordEncoder() { 25 | return new BCryptPasswordEncoder(); 26 | } 27 | 28 | @Bean 29 | public AuthenticationManager authenticationManager() throws Exception { 30 | return super.authenticationManager(); 31 | } 32 | 33 | @Override 34 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 35 | auth.inMemoryAuthentication() 36 | .withUser("hellxz") 37 | .password(passwordEncoder().encode("xyz")) 38 | .authorities(new ArrayList<>(0)); 39 | } 40 | 41 | @Override 42 | protected void configure(HttpSecurity http) throws Exception { 43 | //所有请求必须认证 44 | http.authorizeRequests().anyRequest().authenticated(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /password/password-authorization-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 -------------------------------------------------------------------------------- /password/password-resource-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | password 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | password-resource-server 13 | 14 | 15 | -------------------------------------------------------------------------------- /password/password-resource-server/src/main/java/com/github/hellxz/oauth2/PasswordResourceApp.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PasswordResourceApp { 8 | public static void main(String[] args) { 9 | SpringApplication.run(PasswordResourceApp.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /password/password-resource-server/src/main/java/com/github/hellxz/oauth2/config/ResourceServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.http.SessionCreationPolicy; 7 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 8 | import org.springframework.security.crypto.password.PasswordEncoder; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 12 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 13 | import org.springframework.security.oauth2.provider.token.RemoteTokenServices; 14 | import sun.misc.Resource; 15 | 16 | import java.rmi.Remote; 17 | 18 | @Configuration 19 | @EnableResourceServer 20 | public class ResourceServerConfig extends ResourceServerConfigurerAdapter { 21 | @Bean 22 | public RemoteTokenServices remoteTokenServices() { 23 | final RemoteTokenServices tokenServices = new RemoteTokenServices(); 24 | tokenServices.setClientId("client-a"); 25 | tokenServices.setClientSecret("client-a-secret"); 26 | tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token"); 27 | return tokenServices; 28 | } 29 | 30 | @Override 31 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 32 | resources.stateless(true); 33 | } 34 | 35 | @Override 36 | public void configure(HttpSecurity http) throws Exception { 37 | //session创建策略 38 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); 39 | //所有请求需要认证 40 | http.authorizeRequests().anyRequest().authenticated(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /password/password-resource-server/src/main/java/com/github/hellxz/oauth2/web/controller/ResourceController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.controller; 2 | 3 | import com.github.hellxz.oauth2.web.vo.UserVO; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.security.core.context.SecurityContextHolder; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | public class ResourceController { 13 | private static final Logger log = LoggerFactory.getLogger(ResourceController.class); 14 | 15 | @GetMapping("/user/{username}") 16 | public UserVO user(@PathVariable String username){ 17 | log.info("{}", SecurityContextHolder.getContext().getAuthentication()); 18 | return new UserVO(username, username + "@foxmail.com"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /password/password-resource-server/src/main/java/com/github/hellxz/oauth2/web/vo/UserVO.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.vo; 2 | 3 | public class UserVO { 4 | private String username; 5 | private String email; 6 | 7 | public UserVO(String username, String email) { 8 | this.username = username; 9 | this.email = email; 10 | } 11 | 12 | public String getUsername() { 13 | return username; 14 | } 15 | 16 | public void setUsername(String username) { 17 | this.username = username; 18 | } 19 | 20 | public String getEmail() { 21 | return email; 22 | } 23 | 24 | public void setEmail(String email) { 25 | this.email = email; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /password/password-resource-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 -------------------------------------------------------------------------------- /password/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | spring-security-oauth2-learn 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | password 13 | pom 14 | 15 | password-authorization-server 16 | password-resource-server 17 | 18 | 19 | 20 | 21 | org.springframework.security.oauth 22 | spring-security-oauth2 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /pictures/encoded-jwt3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellxz/spring-security-oauth2-learn/f8c9843f70108fab99e888da8acd780ccace1818/pictures/encoded-jwt3.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | authorization-code 7 | implicit 8 | password 9 | client-credentials 10 | jwt 11 | redis-token-saved 12 | uaa-interface-adapter-demo 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.2.1.RELEASE 18 | 19 | 20 | com.github.hellxz 21 | spring-security-oauth2-learn 22 | 0.0.1-SNAPSHOT 23 | pom 24 | spring-security-oauth2-learn 25 | Spring Security OAuth2 Four Pattern Demo 26 | 27 | 28 | 1.8 29 | 2.4.0.RELEASE 30 | 1.1.0.RELEASE 31 | 32 | 1.2.79 33 | 1.13 34 | 3.9 35 | 36 | 8.0.28 37 | 38 | 2.2.10.RELEASE 39 | 2.11.0 40 | 41 | 5.2.3.RELEASE 42 | 5.2.3.RELEASE 43 | 5.2.3.RELEASE 44 | 45 | 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-dependencies 51 | 2.2.1.RELEASE 52 | 53 | 54 | org.springframework.security.oauth 55 | spring-security-oauth2 56 | ${spring-security-oauth2.version} 57 | 58 | 59 | org.springframework.security 60 | spring-security-jwt 61 | ${spring-security-jwt.version} 62 | 63 | 64 | com.alibaba 65 | fastjson 66 | ${fastjson.version} 67 | 68 | 69 | commons-codec 70 | commons-codec 71 | ${commons-codec.version} 72 | 73 | 74 | org.apache.commons 75 | commons-lang3 76 | ${commons-lang3.version} 77 | 78 | 79 | mysql 80 | mysql-connector-java 81 | ${mysql.version} 82 | 83 | 84 | org.springframework.cloud 85 | spring-cloud-starter-openfeign 86 | ${spring-cloud-starter-openfeign.version} 87 | 88 | 89 | commons-io 90 | commons-io 91 | 92 | 93 | 94 | 95 | commons-io 96 | commons-io 97 | ${commons-io.version} 98 | 99 | 100 | 101 | 102 | 103 | 104 | org.springframework.boot 105 | spring-boot-starter-security 106 | 107 | 108 | 109 | org.springframework.boot 110 | spring-boot-starter-web 111 | 112 | 113 | org.springframework.security 114 | spring-security-test 115 | test 116 | 117 | 118 | org.springframework.boot 119 | spring-boot-starter-test 120 | 121 | 122 | 123 | 124 | 125 | 126 | org.springframework.boot 127 | spring-boot-maven-plugin 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /redis-token-saved/README.md: -------------------------------------------------------------------------------- 1 | # redis-token-saved 2 | ## 简单说明 3 | 此模式用于演示存储access_token\refresh_token到redis中, 4 | 并且提供使用redis来校验token是否正确的资源服务器配置 -------------------------------------------------------------------------------- /redis-token-saved/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | spring-security-oauth2-learn 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | redis-token-saved 13 | pom 14 | 15 | redis-token-saved-authorization-server 16 | redis-token-saved-resource-server 17 | 18 | 19 | 20 | 21 | org.springframework.security.oauth 22 | spring-security-oauth2 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-data-redis 27 | 28 | 29 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-authorization-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | redis-token-saved 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | redis-token-saved-authorization-server 13 | 14 | 15 | 16 | com.alibaba 17 | fastjson 18 | 19 | 20 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-authorization-server/src/main/java/com/github/hellxz/oauth2/RedisAuthorizationServer.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * redis作为token存储的授权server 8 | */ 9 | @SpringBootApplication 10 | public class RedisAuthorizationServer { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(RedisAuthorizationServer.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-authorization-server/src/main/java/com/github/hellxz/oauth2/config/AuthorizationConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.connection.RedisConnectionFactory; 7 | import org.springframework.security.authentication.AuthenticationManager; 8 | import org.springframework.security.core.userdetails.UserDetailsService; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 12 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 13 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 14 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 15 | import org.springframework.security.oauth2.provider.token.DefaultTokenServices; 16 | import org.springframework.security.oauth2.provider.token.TokenStore; 17 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; 18 | 19 | @Configuration 20 | @EnableAuthorizationServer 21 | public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter { 22 | 23 | /** 24 | * redis工厂,默认使用lettue 25 | */ 26 | @Autowired 27 | public RedisConnectionFactory redisConnectionFactory; 28 | 29 | /** 30 | * 用户认证管理器 31 | */ 32 | @Autowired 33 | public AuthenticationManager authenticationManager; 34 | 35 | /** 36 | * 用户服务 37 | */ 38 | @Autowired 39 | public UserDetailsService userDetailsService; 40 | 41 | /** 42 | * 密码加密器 43 | */ 44 | @Autowired 45 | private PasswordEncoder passwordEncoder; 46 | 47 | /** 48 | * 授权服务安全配置,主要用于放行客户端访问授权服务接口 49 | * 50 | * @param security AuthorizationServerSecurityConfigurer 51 | * @throws Exception 异常 52 | */ 53 | @Override 54 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 55 | //允许客户端表单提交 56 | security.allowFormAuthenticationForClients() 57 | //客户端校验token访问许可 58 | .checkTokenAccess("permitAll()") 59 | //客户端token调用许可 60 | .tokenKeyAccess("permitAll()"); 61 | } 62 | 63 | /** 64 | * 客户端信息配置,可配置多个客户端,这里可以使用配置文件进行代替 65 | * 66 | * @param clients 客户端设置 67 | * @throws Exception 异常 68 | */ 69 | @Override 70 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 71 | clients.inMemory() 72 | .withClient("client-a") 73 | .secret(passwordEncoder.encode("client-a-secret")) 74 | .redirectUris("http://localhost:9001/callback") 75 | //支持 授权码、密码两种授权模式,支持刷新token功能 76 | .authorizedGrantTypes("authorization_code", "password", "refresh_token"); 77 | } 78 | 79 | /** 80 | * 配置端点 81 | * 82 | * @param endpoints 端点 83 | * @throws Exception 异常 84 | */ 85 | @Override 86 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 87 | //配置认证管理器 88 | endpoints.authenticationManager(authenticationManager) 89 | //配置用户服务 90 | .userDetailsService(userDetailsService) 91 | //配置token存储的服务与位置 92 | .tokenServices(tokenService()) 93 | .tokenStore(tokenStore()); 94 | } 95 | 96 | @Bean 97 | public TokenStore tokenStore() { 98 | //使用redis存储token 99 | RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory); 100 | //设置redis token存储中的前缀 101 | redisTokenStore.setPrefix("auth-token:"); 102 | return redisTokenStore; 103 | } 104 | 105 | @Bean 106 | public DefaultTokenServices tokenService() { 107 | DefaultTokenServices tokenServices = new DefaultTokenServices(); 108 | //配置token存储 109 | tokenServices.setTokenStore(tokenStore()); 110 | //开启支持refresh_token,此处如果之前没有配置,启动服务后再配置重启服务,可能会导致不返回token的问题,解决方式:清除redis对应token存储 111 | tokenServices.setSupportRefreshToken(true); 112 | //复用refresh_token 113 | tokenServices.setReuseRefreshToken(true); 114 | //token有效期,设置12小时 115 | tokenServices.setAccessTokenValiditySeconds(12 * 60 * 60); 116 | //refresh_token有效期,设置一周 117 | tokenServices.setRefreshTokenValiditySeconds(7 * 24 * 60 * 60); 118 | return tokenServices; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-authorization-server/src/main/java/com/github/hellxz/oauth2/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.http.HttpMethod; 6 | import org.springframework.security.authentication.AuthenticationManager; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.core.authority.AuthorityUtils; 12 | import org.springframework.security.core.userdetails.UserDetailsService; 13 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 14 | import org.springframework.security.crypto.password.PasswordEncoder; 15 | 16 | @Configuration 17 | @EnableWebSecurity 18 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 19 | 20 | @Bean 21 | public PasswordEncoder passwordEncoder() { 22 | return new BCryptPasswordEncoder(); 23 | } 24 | 25 | /** 26 | * 配置认证管理器信息,这里可以使用UserDetailsService实现类来提供用户信息,或Provider+UserDetailsService 27 | * 28 | * @param auth 认证管理器配置 29 | * @throws Exception 异常 30 | */ 31 | @Override 32 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 33 | //@formatter:off 34 | auth.inMemoryAuthentication() 35 | .withUser("hellxz") 36 | .password(passwordEncoder().encode("test")) 37 | .authorities(AuthorityUtils.createAuthorityList("all")); 38 | //@formatter:on 39 | } 40 | 41 | /** 42 | * 配置http访问控制 43 | * 44 | * @param http http安全配置 45 | * @throws Exception 异常 46 | */ 47 | @Override 48 | protected void configure(HttpSecurity http) throws Exception { 49 | http.authorizeRequests() 50 | //放行options方法请求 51 | .antMatchers(HttpMethod.OPTIONS).permitAll() 52 | .anyRequest().authenticated() 53 | .and() 54 | .csrf().disable(); 55 | } 56 | 57 | @Bean 58 | public AuthenticationManager authenticationManager() throws Exception { 59 | return super.authenticationManager(); 60 | } 61 | 62 | @Bean 63 | public UserDetailsService userDetailsService() { 64 | return super.userDetailsService(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-authorization-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | spring: 5 | redis: 6 | host: 127.0.0.1 7 | port: 6379 8 | password: 123 9 | database: 0 10 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-authorization-server/src/test/java/com/github/hellxz/auth2/RedisTokenSavedServerTest.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.auth2; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.github.hellxz.oauth2.RedisAuthorizationServer; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.http.MediaType; 13 | import org.springframework.security.web.FilterChainProxy; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | import org.springframework.test.web.servlet.MockMvc; 16 | import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; 17 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 18 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 19 | import org.springframework.util.StringUtils; 20 | import org.springframework.web.context.WebApplicationContext; 21 | 22 | import java.nio.charset.StandardCharsets; 23 | import java.util.Base64; 24 | 25 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 26 | 27 | @RunWith(SpringRunner.class) 28 | @SpringBootTest(classes = {RedisAuthorizationServer.class}) 29 | public class RedisTokenSavedServerTest { 30 | private static final Logger log = LoggerFactory.getLogger(RedisTokenSavedServerTest.class); 31 | 32 | @Autowired 33 | private WebApplicationContext context; 34 | @Autowired 35 | private FilterChainProxy springSecurityFilterChain; 36 | private MockMvc mockMvc; 37 | 38 | @Before 39 | public void init(){ 40 | //初始化web上下文,需要包含spring security filter chain 41 | mockMvc = MockMvcBuilders.webAppContextSetup(context).addFilter(springSecurityFilterChain).build(); 42 | } 43 | 44 | @Test 45 | public void getAccessTokenTest() throws Exception { 46 | MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post("http://localhost:8080/oauth/token") 47 | .header("Authorization", "Basic " 48 | + Base64.getEncoder().encodeToString("client-a:client-a-secret".getBytes(StandardCharsets.UTF_8))) 49 | .accept(MediaType.APPLICATION_JSON) 50 | .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE) 51 | .param("username", "hellxz") 52 | .param("password", "test") 53 | .param("grant_type", "password") 54 | .param("scope", "all"); 55 | String result = mockMvc.perform(request) 56 | .andExpect(status().is2xxSuccessful()) 57 | .andReturn().getResponse().getContentAsString(); 58 | if(!StringUtils.isEmpty(result)){ 59 | log.info(result); 60 | } 61 | } 62 | 63 | @Test 64 | public void checkTokenTest() throws Exception{ 65 | MockHttpServletRequestBuilder getAccessTokenRequest = MockMvcRequestBuilders.post("http://localhost:8080/oauth/token") 66 | .header("Authorization", "Basic " 67 | + Base64.getEncoder().encodeToString("client-a:client-a-secret".getBytes(StandardCharsets.UTF_8))) 68 | .accept(MediaType.APPLICATION_JSON) 69 | .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE) 70 | .param("username", "hellxz") 71 | .param("password", "test") 72 | .param("grant_type", "password") 73 | .param("scope", "all"); 74 | String accessTokenJson = mockMvc.perform(getAccessTokenRequest) 75 | .andExpect(status().is2xxSuccessful()) 76 | .andReturn().getResponse().getContentAsString(); 77 | 78 | JSONObject jsonObject = JSONObject.parseObject(accessTokenJson); 79 | MockHttpServletRequestBuilder checkTokenRequest = MockMvcRequestBuilders.post("http://localhost:8080/oauth/check_token") 80 | .header("Authorization", "Basic " 81 | + Base64.getEncoder().encodeToString("client-a:client-a-secret".getBytes(StandardCharsets.UTF_8))) 82 | .accept(MediaType.APPLICATION_JSON) 83 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 84 | .param("token", jsonObject.getString("access_token")); 85 | String responseBody = mockMvc.perform(checkTokenRequest) 86 | .andExpect(status().is2xxSuccessful()) 87 | .andReturn().getResponse().getContentAsString(); 88 | if(!StringUtils.isEmpty(responseBody)){ 89 | log.info(responseBody); 90 | } 91 | } 92 | 93 | @Test 94 | public void refreshTokenTest() throws Exception { 95 | MockHttpServletRequestBuilder getAccessTokenRequest = MockMvcRequestBuilders.post("http://localhost:8080/oauth/token") 96 | .header("Authorization", "Basic " 97 | + Base64.getEncoder().encodeToString("client-a:client-a-secret".getBytes(StandardCharsets.UTF_8))) 98 | .accept(MediaType.APPLICATION_JSON) 99 | .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE) 100 | .param("username", "hellxz") 101 | .param("password", "test") 102 | .param("grant_type", "password") 103 | .param("scope", "all"); 104 | String accessTokenJson = mockMvc.perform(getAccessTokenRequest) 105 | .andExpect(status().is2xxSuccessful()) 106 | .andReturn().getResponse().getContentAsString(); 107 | 108 | JSONObject jsonObject = JSONObject.parseObject(accessTokenJson); 109 | MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post("http://localhost:8080/oauth/token") 110 | .header("Authorization", "Basic " 111 | + Base64.getEncoder().encodeToString("client-a:client-a-secret".getBytes(StandardCharsets.UTF_8))) 112 | .accept(MediaType.APPLICATION_JSON) 113 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 114 | .param("refresh_token", jsonObject.getString("refresh_token")) 115 | .param("grant_type", "refresh_token") 116 | .param("scope", "all"); 117 | String tokenJson = mockMvc.perform(request) 118 | .andExpect(status().is2xxSuccessful()) 119 | .andReturn().getResponse().getContentAsString(); 120 | if(!StringUtils.isEmpty(tokenJson)){ 121 | log.info(tokenJson); 122 | } 123 | } 124 | 125 | // @Test 126 | // public void revokeTokenTest() throws Exception { 127 | // MockHttpServletRequestBuilder getAccessTokenRequest = MockMvcRequestBuilders.post("http://localhost:8080/oauth/token") 128 | // .header("Authorization", "Basic " 129 | // + Base64.getEncoder().encodeToString("client-a:client-a-secret".getBytes(StandardCharsets.UTF_8))) 130 | // .accept(MediaType.APPLICATION_JSON) 131 | // .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE) 132 | // .param("username", "hellxz") 133 | // .param("password", "test") 134 | // .param("grant_type", "password") 135 | // .param("scope", "all"); 136 | // String accessTokenJson = mockMvc.perform(getAccessTokenRequest) 137 | // .andExpect(status().is2xxSuccessful()) 138 | // .andReturn().getResponse().getContentAsString(); 139 | // 140 | // JSONObject jsonObject = JSONObject.parseObject(accessTokenJson); 141 | // MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post("http://localhost:8080/logout") 142 | // .header("Authorization", "Bearer " + jsonObject.getString("access_token")) 143 | // .accept(MediaType.APPLICATION_JSON) 144 | // .contentType(MediaType.APPLICATION_FORM_URLENCODED); 145 | // String revokeResult = mockMvc.perform(request) 146 | // .andExpect(status().is2xxSuccessful()) 147 | // .andReturn().getResponse().getContentAsString(); 148 | // if(!StringUtils.isEmpty(revokeResult)){ 149 | // log.info(revokeResult); 150 | // } 151 | // } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-resource-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | redis-token-saved 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | redis-token-saved-resource-server 13 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-resource-server/src/main/java/com/github/hellxz/oauth2/RedisResourceServer.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * 使用redis作为token存储的资源服务器,这里不使用调用授权服务器的方式去校验资源,只需要从redis中取token进行判断即可 8 | */ 9 | @SpringBootApplication 10 | public class RedisResourceServer { 11 | public static void main(String[] args) { 12 | SpringApplication.run(RedisResourceServer.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-resource-server/src/main/java/com/github/hellxz/oauth2/config/ResourceServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.connection.RedisConnectionFactory; 7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 10 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 11 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; 12 | 13 | @Configuration 14 | @EnableResourceServer 15 | public class ResourceServerConfig extends ResourceServerConfigurerAdapter { 16 | 17 | @Autowired 18 | private RedisConnectionFactory redisConnectionFactory; 19 | 20 | @Override 21 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 22 | //无状态 23 | resources.stateless(true); 24 | //设置token存储 25 | resources.tokenStore(tokenStore()); 26 | } 27 | 28 | /** 29 | * 设置token存储,这一点配置要与授权服务器相一致 30 | */ 31 | @Bean 32 | public RedisTokenStore tokenStore(){ 33 | RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory); 34 | redisTokenStore.setPrefix("auth-token:"); 35 | return redisTokenStore; 36 | } 37 | 38 | @Override 39 | public void configure(HttpSecurity http) throws Exception { 40 | http.csrf().disable() 41 | .authorizeRequests() 42 | .anyRequest().authenticated() 43 | .and() 44 | .httpBasic(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-resource-server/src/main/java/com/github/hellxz/oauth2/web/controller/ResourceController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.controller; 2 | 3 | import com.github.hellxz.oauth2.web.vo.UserVO; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.security.core.context.SecurityContextHolder; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | public class ResourceController { 13 | private static final Logger log = LoggerFactory.getLogger(ResourceController.class); 14 | 15 | @GetMapping("/user/{username}") 16 | public UserVO user(@PathVariable String username){ 17 | log.info("{}", SecurityContextHolder.getContext().getAuthentication()); 18 | return new UserVO(username, username + "@foxmail.com"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-resource-server/src/main/java/com/github/hellxz/oauth2/web/vo/UserVO.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.web.vo; 2 | 3 | public class UserVO { 4 | private String username; 5 | private String email; 6 | 7 | public UserVO(String username, String email) { 8 | this.username = username; 9 | this.email = email; 10 | } 11 | 12 | public String getUsername() { 13 | return username; 14 | } 15 | 16 | public void setUsername(String username) { 17 | this.username = username; 18 | } 19 | 20 | public String getEmail() { 21 | return email; 22 | } 23 | 24 | public void setEmail(String email) { 25 | this.email = email; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /redis-token-saved/redis-token-saved-resource-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8081 3 | 4 | spring: 5 | redis: 6 | host: 127.0.0.1 7 | port: 6379 8 | password: 123 9 | database: 0 10 | -------------------------------------------------------------------------------- /uaa-interface-adapter-demo/README.md: -------------------------------------------------------------------------------- 1 | # uaa-interface-adapter-demo 2 | 使用OAuth2提供的工具类,在不重写源码的情况下,使用Api接口层面进行适配接口 3 | 暂适配了密码模式与客户端模式接口 4 | 5 | 使用的授权服务模式为jwt的`jwt-authorization-server`模块 -------------------------------------------------------------------------------- /uaa-interface-adapter-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | spring-security-oauth2-learn 7 | com.github.hellxz 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | uaa-interface-adapter-demo 13 | 14 | 15 | org.springframework.security.oauth 16 | spring-security-oauth2 17 | 18 | 19 | com.alibaba 20 | fastjson 21 | 22 | 23 | commons-codec 24 | commons-codec 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /uaa-interface-adapter-demo/src/main/java/com/github/hellxz/oauth2/demo/UaaAdapterApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UaaAdapterApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(UaaAdapterApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /uaa-interface-adapter-demo/src/main/java/com/github/hellxz/oauth2/demo/config/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.demo.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 | 8 | @Configuration 9 | @EnableWebSecurity 10 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 11 | @Override 12 | protected void configure(HttpSecurity http) throws Exception { 13 | http.authorizeRequests() 14 | .antMatchers("/api/*/login").permitAll() 15 | .anyRequest().authenticated(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /uaa-interface-adapter-demo/src/main/java/com/github/hellxz/oauth2/demo/controller/UaaAdapterController.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.demo.controller; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.github.hellxz.oauth2.demo.utils.Response; 5 | import org.apache.commons.codec.binary.Base64; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException; 10 | import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest; 11 | import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider; 12 | import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; 13 | import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider; 14 | import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails; 15 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.RequestHeader; 18 | import org.springframework.web.bind.annotation.RequestParam; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | import java.nio.charset.StandardCharsets; 22 | import java.util.Arrays; 23 | import java.util.Collections; 24 | 25 | /** 26 | * 授权Api适配controller 27 | */ 28 | @RestController 29 | @SuppressWarnings("deprecation") 30 | public class UaaAdapterController { 31 | private static final Logger log = LoggerFactory.getLogger(UaaAdapterController.class); 32 | 33 | @Value("${custom.uaa-uri}") 34 | String uaaUri; 35 | 36 | @GetMapping("/api/user/login") 37 | public Response userLogin(@RequestHeader("Authorization") String authorization, 38 | @RequestParam String username, @RequestParam String password) { 39 | ResourceOwnerPasswordAccessTokenProvider provider = new ResourceOwnerPasswordAccessTokenProvider(); 40 | ResourceOwnerPasswordResourceDetails passwordResourceDetails = 41 | obtainPasswordResourceDetails(authorization, username, password); 42 | OAuth2AccessToken oAuth2AccessToken = null; 43 | try { 44 | oAuth2AccessToken = provider.obtainAccessToken(passwordResourceDetails, 45 | new DefaultAccessTokenRequest()); 46 | } catch (OAuth2AccessDeniedException accessDeniedException) { 47 | log.error("获取访问token失败", accessDeniedException); 48 | return new Response().err("获取访问token失败", accessDeniedException.getStackTrace().toString()); 49 | } 50 | return new Response().ok(oAuth2AccessToken); 51 | } 52 | 53 | @GetMapping("/api/client/login") 54 | public Response clientLogin(@RequestHeader("Authorization") String authorization){ 55 | ClientCredentialsAccessTokenProvider clientCredentialsAccessTokenProvider = new ClientCredentialsAccessTokenProvider(); 56 | ClientCredentialsResourceDetails clientCredentialsResourceDetails = obtainClientCredentialResourceDetails(authorization); 57 | 58 | OAuth2AccessToken oAuth2AccessToken = null; 59 | try{ 60 | oAuth2AccessToken = clientCredentialsAccessTokenProvider.obtainAccessToken( 61 | clientCredentialsResourceDetails, new DefaultAccessTokenRequest()); 62 | }catch(OAuth2AccessDeniedException accessDeniedException){ 63 | log.error("获取访问token失败", accessDeniedException); 64 | return new Response().err("获取访问token失败", accessDeniedException.getStackTrace().toString()); 65 | } 66 | return new Response().ok(oAuth2AccessToken); 67 | } 68 | 69 | private ResourceOwnerPasswordResourceDetails obtainPasswordResourceDetails( 70 | String authorization, String username, String password) { 71 | ResourceOwnerPasswordResourceDetails passwordResourceDetails = new ResourceOwnerPasswordResourceDetails(); 72 | passwordResourceDetails.setUsername(username); 73 | passwordResourceDetails.setPassword(password); 74 | JSONObject clientInfo = getClientInfoFromAuthorization(authorization); 75 | passwordResourceDetails.setClientId(clientInfo.getString("clientId")); 76 | passwordResourceDetails.setClientSecret(clientInfo.getString("clientSecret")); 77 | String[] scopes = {"users"}; 78 | passwordResourceDetails.setScope(Arrays.asList(scopes)); 79 | passwordResourceDetails.setAccessTokenUri(uaaUri); 80 | return passwordResourceDetails; 81 | } 82 | 83 | private ClientCredentialsResourceDetails obtainClientCredentialResourceDetails(String authorization){ 84 | ClientCredentialsResourceDetails clientCredentialsResourceDetails = new ClientCredentialsResourceDetails(); 85 | JSONObject clientInfo = getClientInfoFromAuthorization(authorization); 86 | clientCredentialsResourceDetails.setClientId(clientInfo.getString("clientId")); 87 | clientCredentialsResourceDetails.setClientSecret(clientInfo.getString("clientSecret")); 88 | clientCredentialsResourceDetails.setScope(Collections.singletonList("service")); 89 | clientCredentialsResourceDetails.setAccessTokenUri(uaaUri); 90 | return clientCredentialsResourceDetails; 91 | } 92 | 93 | private JSONObject getClientInfoFromAuthorization(String authorization) { 94 | if(!authorization.toLowerCase().startsWith("basic")){ 95 | throw new RuntimeException("解析请求头失败"); 96 | } 97 | String basic = authorization.replace("Basic", "").trim(); 98 | byte[] decode = Base64.decodeBase64(basic.getBytes(StandardCharsets.UTF_8)); 99 | String contractStr = new String(decode); 100 | if (!contractStr.contains(":")){ 101 | throw new RuntimeException("解析请求头失败"); 102 | } 103 | String[] clientInfoArray = contractStr.split(":", 2); 104 | JSONObject json = new JSONObject(); 105 | json.put("clientId", clientInfoArray[0]); 106 | json.put("clientSecret", clientInfoArray[1]); 107 | return json; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /uaa-interface-adapter-demo/src/main/java/com/github/hellxz/oauth2/demo/utils/Response.java: -------------------------------------------------------------------------------- 1 | package com.github.hellxz.oauth2.demo.utils; 2 | 3 | /** 4 | * 响应工具类 5 | */ 6 | public class Response { 7 | Integer code; 8 | String msg; 9 | T data; 10 | 11 | public Response() { 12 | } 13 | 14 | public Response(Integer code, String msg, T data) { 15 | this.code = code; 16 | this.msg = msg; 17 | this.data = data; 18 | } 19 | 20 | public Response(Integer code, String msg) { 21 | this.code = code; 22 | this.msg = msg; 23 | this.data = null; 24 | } 25 | 26 | public Response ok(String msg) { 27 | return new Response(200, msg); 28 | } 29 | 30 | public Response ok(T data) { 31 | return new Response<>(200, "成功", data); 32 | } 33 | 34 | public Response ok(String msg, T data) { 35 | return new Response<>(200, msg, data); 36 | } 37 | 38 | public Response err(String msg){ 39 | return new Response<>(500, msg); 40 | } 41 | 42 | public Response err(Integer code, String msg){ 43 | return new Response<>(code, msg); 44 | } 45 | 46 | public Response err(String msg, T data){ 47 | return new Response<>(500, msg, data); 48 | } 49 | 50 | public Response err(Integer code, String msg, T data){ 51 | return new Response<>(code, msg, data); 52 | } 53 | 54 | public Integer getCode() { 55 | return code; 56 | } 57 | 58 | public void setCode(Integer code) { 59 | this.code = code; 60 | } 61 | 62 | public String getMsg() { 63 | return msg; 64 | } 65 | 66 | public void setMsg(String msg) { 67 | this.msg = msg; 68 | } 69 | 70 | public T getData() { 71 | return data; 72 | } 73 | 74 | public void setData(T data) { 75 | this.data = data; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /uaa-interface-adapter-demo/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9001 3 | custom: 4 | uaa-uri: http://localhost:8080/oauth/token --------------------------------------------------------------------------------