如果您正在寻找JWT实施,请点击此链接

本指南逐步介绍了使用Spring Boot 2创建集中式身份验证和授权服务器的过程,还将提供演示资源服务器。

如果您不熟悉OAuth2,建议您阅读此书。

先决条件

  • JDK 1.8
  • 文本编辑器或您喜欢的IDE
  • Maven 3.0+

实施概述

对于这个项目,我们将通过Spring Boot使用Spring Security 5 。 如果您熟悉早期版本,那么《 Spring Boot迁移指南》可能会有用。

OAuth2术语

  • 资源所有者

    • 授权应用程序访问其帐户的用户。
  • 资源服务器
    • client获取access token之后处理已认证请求的服务器。
  • 客户
    • 代表资源所有者访问受保护资源的应用程序。
  • 授权服务器
    • 在成功验证clientresource owner并授权请求之后,发出访问令牌的服务器。
  • 访问令牌
    • 用于访问受保护资源的唯一令牌
  • 范围
    • 许可
  • 赠款类型
    • grant是一种获取访问令牌的方法。

授权服务器

为了构建我们的Authorization Server我们将通过Spring Boot 2.0.x使用Spring Security5.x 。

依存关系

您可以转到start.spring.io并生成一个新项目,然后添加以下依赖项:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>2.1.2.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>   </dependencies>

数据库

出于本指南的考虑,我们将使用H2数据库 。
在这里,您可以找到Spring Security所需的参考OAuth2 SQL模式。

CREATE TABLE IF NOT EXISTS oauth_client_details (client_id VARCHAR(256) PRIMARY KEY,resource_ids VARCHAR(256),client_secret VARCHAR(256) NOT NULL,scope VARCHAR(256),authorized_grant_types VARCHAR(256),web_server_redirect_uri VARCHAR(256),authorities VARCHAR(256),access_token_validity INTEGER,refresh_token_validity INTEGER,additional_information VARCHAR(4000),autoapprove VARCHAR(256)
);CREATE TABLE IF NOT EXISTS oauth_client_token (token_id VARCHAR(256),token BLOB,authentication_id VARCHAR(256) PRIMARY KEY,user_name VARCHAR(256),client_id VARCHAR(256)
);CREATE TABLE IF NOT EXISTS oauth_access_token (token_id VARCHAR(256),token BLOB,authentication_id VARCHAR(256),user_name VARCHAR(256),client_id VARCHAR(256),authentication BLOB,refresh_token VARCHAR(256)
);CREATE TABLE IF NOT EXISTS oauth_refresh_token (token_id VARCHAR(256),token BLOB,authentication BLOB
);CREATE TABLE IF NOT EXISTS oauth_code (code VARCHAR(256), authentication BLOB
);

然后添加以下条目

-- The encrypted client_secret it `secret`
INSERT INTO oauth_client_details (client_id, client_secret, scope, authorized_grant_types, authorities, access_token_validity)VALUES ('clientId', '{bcrypt}$2a$10$vCXMWCn7fDZWOcLnIEhmK.74dvK1Eh8ae2WrWlhr2ETPLoxQctN4.', 'read,write', 'password,refresh_token,client_credentials', 'ROLE_CLIENT', 300);

上面的client_secret是使用bcrypt生成的。
前缀{bcrypt}是必需的,因为我们将使用Spring Security 5.x的DelegatingPasswordEncoder的新功能。

在下面的页面中,您可以找到Spring的org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl使用的UserAuthority参考SQL模式。

CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(256) NOT NULL,password VARCHAR(256) NOT NULL,enabled TINYINT(1),UNIQUE KEY unique_username(username)
);CREATE TABLE IF NOT EXISTS authorities (username VARCHAR(256) NOT NULL,authority VARCHAR(256) NOT NULL,PRIMARY KEY(username, authority)
);

与之前相同,为用户及其权限添加以下条目。

-- The encrypted password is `pass`
INSERT INTO users (id, username, password, enabled) VALUES (1, 'user', '{bcrypt}$2a$10$cyf5NfobcruKQ8XGjUJkEegr9ZWFqaea6vjpXWEaSqTa2xL9wjgQC', 1);
INSERT INTO authorities (username, authority) VALUES ('user', 'ROLE_USER');

Spring安全配置

添加以下Spring配置类。

import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;import javax.sql.DataSource;@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {private final DataSource dataSource;private PasswordEncoder passwordEncoder;private UserDetailsService userDetailsService;public WebSecurityConfiguration(final DataSource dataSource) {this.dataSource = dataSource;}@Overrideprotected void configure(final AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Beanpublic PasswordEncoder passwordEncoder() {if (passwordEncoder == null) {passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();}return passwordEncoder;}@Beanpublic UserDetailsService userDetailsService() {if (userDetailsService == null) {userDetailsService = new JdbcDaoImpl();((JdbcDaoImpl) userDetailsService).setDataSource(dataSource);}return userDetailsService;}}

引用Spring Blog :

@EnableWebSecurity批注和WebSecurityConfigurerAdapter一起提供基于Web的安全性。

如果您使用的是Spring Boot,则将自动配置DataSource对象,您可以将其注入到类中,而不必自己定义。 需要将其注入到UserDetailsService中,该服务将使用Spring Security提供的JdbcDaoImpl ,如有必要,您可以将其替换为自己的实现。

由于某些自动配置的Spring @Bean需要Spring Security的AuthenticationManager因此有必要重写authenticationManagerBean方法,并以@Bean authenticationManagerBean注释。

PasswordEncoder将由PasswordEncoderFactories.createDelegatingPasswordEncoder()处理,其中基于前缀处理一些密码编码器和委托,在我们的示例中,我们使用{bcrypt}作为密码的前缀。

授权服务器配置

授权服务器验证clientuser凭证并提供令牌。

添加以下Spring配置类。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;import javax.sql.DataSource;@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {private final DataSource dataSource;private final PasswordEncoder passwordEncoder;private final AuthenticationManager authenticationManager;private TokenStore tokenStore;public AuthorizationServerConfiguration(final DataSource dataSource, final PasswordEncoder passwordEncoder,final AuthenticationManager authenticationManager) {this.dataSource = dataSource;this.passwordEncoder = passwordEncoder;this.authenticationManager = authenticationManager;}@Beanpublic TokenStore tokenStore() {if (tokenStore == null) {tokenStore = new JdbcTokenStore(dataSource);}return tokenStore;}@Beanpublic DefaultTokenServices tokenServices(final ClientDetailsService clientDetailsService) {DefaultTokenServices tokenServices = new DefaultTokenServices();tokenServices.setSupportRefreshToken(true);tokenServices.setTokenStore(tokenStore());tokenServices.setClientDetailsService(clientDetailsService);tokenServices.setAuthenticationManager(authenticationManager);return tokenServices;}@Overridepublic void configure(final ClientDetailsServiceConfigurer clients) throws Exception {clients.jdbc(dataSource);}@Overridepublic void configure(final AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore());}@Overridepublic void configure(final AuthorizationServerSecurityConfigurer oauthServer) {oauthServer.passwordEncoder(passwordEncoder).tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}}

用户信息端点

现在,我们需要定义一个端点,在该端点上可以将授权令牌解码为Authorization对象,以添加以下类。

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.security.Principal;@RestController
@RequestMapping("/profile")
public class UserController {@GetMapping("/me")public ResponseEntityget(final Principal principal) {return ResponseEntity.ok(principal);}}

资源服务器配置

资源服务器托管HTTP资源 ,其中的HTTP资源可以是文档,照片或其他内容,在我们的情况下,它将是受OAuth2保护的REST API。

依存关系

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>2.1.2.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency>                </dependencies>

定义我们受保护的API

下面的代码定义了端点/me并返回Principal对象,它要求经过身份验证的用户具有ROLE_USER的访问权限。

import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.security.Principal;@RestController
@RequestMapping("/me")
public class UserController {@GetMapping@PreAuthorize("hasRole('ROLE_USER')")public ResponseEntity<Principal> get(final Principal principal) {return ResponseEntity.ok(principal);}}

@PreAuthorize批注会在执行代码之前验证用户是否具有给定角色,以使其正常工作,有必要启用prePost批注,为此添加以下类:

import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration {}

这里的重要部分是@EnableGlobalMethodSecurity(prePostEnabled = true)批注, prePostEnabled标志默认情况下设置为false ,将其设置为true可使@PreAuthorize批注起作用。

资源服务器配置

现在,让我们为资源服务器添加Spring的配置。

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {}

来自Javadoc的@EnableResourceServer批注:

OAuth2资源服务器的便捷注释,可启用Spring Security过滤器,该过滤器通过传入的OAuth2令牌对请求进行身份验证。 用户应添加此批注并提供类型为{@link ResourceServerConfigurer}的@Bean (例如,通过{@link ResourceServerConfigurerAdapter}),用于指定资源的详细信息(URL路径和资源ID)。 为了使用此过滤器,您必须在应用程序中的某个位置{@link EnableWebSecurity},使用该注释的位置相同,也可以使用其他位置。

现在我们已经准备好所有必需的代码,我们需要配置RemoteTokenServices ,对我们来说幸运的是,Spring提供了一个配置属性,可以在其中设置可以将令牌转换为Authentication对象的url。

security:oauth2:resource:user-info-uri: http://localhost:9001/profile/me

一起测试

为了一起测试,我们需要同时旋转Authorization ServerResource Server ,在我的设置中,它将相应地在端口90019101上运行。

生成令牌

$ curl -u clientId:secret -X POST localhost:9001/oauth/token\?grant_type=password\&username=user\&password=pass{"access_token" : "e47876b0-9962-41f1-ace3-e3381250ccea","token_type" : "bearer","refresh_token" : "8e17a71c-cb39-4904-8205-4d9f8c71aeef","expires_in" : 299,"scope" : "read write"
}

访问资源

既然已经生成了令牌,请复制access_token并将其添加到Authorization HTTP Header上的请求中,例如:

$ curl -i localhost:9101/me -H "Authorization: Bearer c06a4137-fa07-4d9a-97f9-85d1ba820d3a"{"authorities" : [ {"authority" : "ROLE_USER"} ],"details" : {"remoteAddress" : "127.0.0.1","sessionId" : null,"tokenValue" : "c06a4137-fa07-4d9a-97f9-85d1ba820d3a","tokenType" : "Bearer","decodedDetails" : null},"authenticated" : true,"userAuthentication" : {"authorities" : [ {"authority" : "ROLE_USER"} ],"details" : {"authorities" : [ {"authority" : "ROLE_USER"} ],"details" : {"remoteAddress" : "127.0.0.1","sessionId" : null,"tokenValue" : "c06a4137-fa07-4d9a-97f9-85d1ba820d3a","tokenType" : "Bearer","decodedDetails" : null},"authenticated" : true,"userAuthentication" : {"authorities" : [ {"authority" : "ROLE_USER"} ],"details" : {"grant_type" : "password","username" : "user"},"authenticated" : true,"principal" : {"password" : null,"username" : "user","authorities" : [ {"authority" : "ROLE_USER"} ],"accountNonExpired" : true,"accountNonLocked" : true,"credentialsNonExpired" : true,"enabled" : true},"credentials" : null,"name" : "user"},"clientOnly" : false,"oauth2Request" : {"clientId" : "clientId","scope" : [ "read", "write" ],"requestParameters" : {"grant_type" : "password","username" : "user"},"resourceIds" : [ ],"authorities" : [ {"authority" : "ROLE_CLIENT"} ],"approved" : true,"refresh" : false,"redirectUri" : null,"responseTypes" : [ ],"extensions" : { },"grantType" : "password","refreshTokenRequest" : null},"credentials" : "","principal" : {"password" : null,"username" : "user","authorities" : [ {"authority" : "ROLE_USER"} ],"accountNonExpired" : true,"accountNonLocked" : true,"credentialsNonExpired" : true,"enabled" : true},"name" : "user"},"authenticated" : true,"principal" : "user","credentials" : "N/A","name" : "user"},"principal" : "user","credentials" : "","clientOnly" : false,"oauth2Request" : {"clientId" : null,"scope" : [ ],"requestParameters" : { },"resourceIds" : [ ],"authorities" : [ ],"approved" : true,"refresh" : false,"redirectUri" : null,"responseTypes" : [ ],"extensions" : { },"grantType" : null,"refreshTokenRequest" : null},"name" : "user"
}

脚注

  • 可以在GitHub上找到本指南使用的代码
  • OAuth 2.0
  • Spring Security Java配置预览
  • Spring Boot 2 –迁移指南
  • Spring– OAuth2开发人员指南

翻译自: https://www.javacodegeeks.com/2019/03/centralized-authorization-with-oauth2-opaque-tokens-using-spring-boot-2.html

使用Spring Boot 2使用OAuth2和不透明令牌进行集中授权相关推荐

  1. 使用Spring Boot 2通过OAuth2和JWT进行集中授权

    本指南逐步介绍了使用Spring Boot 2创建集中式身份验证和授权服务器的过程,还将提供演示资源服务器. 如果您不熟悉OAuth2,建议您阅读此书. 先决条件 JDK 1.8 文本编辑器或您喜欢的 ...

  2. Spring Boot Security 整合 OAuth2 设计安全API接口服务

    OAuth2概述 oauth2根据使用场景不同,分成了4种模式 授权码模式(authorization code) 简化模式(implicit) 密码模式(resource owner passwor ...

  3. (附源码)Spring Boot 框架整合 OAuth2 实现单点登录 SSO 详细完整源码教程!

    1.  前言 技术这东西吧,看别人写的好像很简单似的,到自己去写的时候就各种问题,"一看就会,一做就错".网上关于实现SSO的文章一大堆,但是当你真的照着写的时候就会发现根本不是那 ...

  4. 【Spring Boot】Spring Boot @EnableOAuth2Sso | 启用 OAuth2 单点登录

    文章目录 演示工具版本 Maven 依赖 使用 @EnableOAuth2Sso OAuth2 配置 登出 完整示例 输出 参考文献 源码下载 本页将介绍Spring Security OAuth2 ...

  5. springboot oauth2登录成功处理器_Spring Boot Security 整合 OAuth2 设计安全API接口服务...

    简介 OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版.本文重点讲解Spring Boot项目对OAuth2进行的实现,如果你对OAut ...

  6. Spring Boot 2.1 版本变化[翻译]

    大家好,我是烤鸭: ​ 最近在把低版本的springboot项目升级,正好翻译了下springboot 2.1-2.3 版本的更新日志. ​ Github 原文:https://github.com/ ...

  7. 项目服务接口设计_Spring Boot Security 整合 OAuth2 设计安全API接口服务

    简介 OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版.本文重点讲解Spring Boot项目对OAuth2进行的实现,如果你对OAut ...

  8. 从零开始实现 Spring Boot 简易读写分离,其实也不难嘛!

    >>号外:关注"Java精选"公众号,菜单栏->聚合->干货分享,回复关键词领取视频资料.开源项目. 最近在学习Spring boot,写了个读写分离.并未 ...

  9. twilio_15分钟内使用Twilio和Stormpath在Spring Boot中进行身份管理

    twilio 建筑物身份管理,包括身份验证和授权? 尝试Stormpath! 我们的REST API和强大的Java SDK支持可以消除您的安全风险,并且可以在几分钟内实现. 注册 ,再也不会建立au ...

最新文章

  1. lodop打印技巧与注意事项
  2. Windos消息驱动
  3. 【知识发现】python开源哈夫曼编码库huffman
  4. 20个堪称神器的命令行软件
  5. 离开小厂进大厂的第一周,BTAJ大厂最新面试题汇集,面试总结
  6. java -web html5学习1
  7. 100人每人100元每次一人分1元给另一人问题matalb 求解
  8. mysql 并行复制原理_MySQL 5.7 并行复制实现原理与调优
  9. 485通信c语言编程linux,485通讯问题(C语言)
  10. HTML 5 新标签
  11. Pygame教程(非常详细)
  12. http://download.chinaitlab.com/special/javadownload.htm
  13. vb 运行错误429 mysql_win7系统运行VB工具提示“运行时错误429 ActiveX部件不能创建对象”的解决方法...
  14. DFS/BFS+思维 HDOJ 5325 Crazy Bobo
  15. 电脑录音软件哪个比较专业
  16. win10易升_小科普 | 彻底关闭Win10自动更新
  17. OpenGL学习三十九:飘动的旗帜
  18. C语言顺序表:1、顺序表的存储、2、顺序表的实现.
  19. 小程序RSA加密 - 公钥加密
  20. PS教程:仙气十足的摄影后期技巧

热门文章

  1. ssl初一组周六模拟赛【2018.4.7】
  2. P4564 [CTSC2018]假面(期望)
  3. Wannafly挑战赛18
  4. 动态规划训练23 [Making the Grade POJ - 3666 ]
  5. 23、java中的网编基础
  6. Photoshop图像修饰工具
  7. 2019蓝桥杯省赛---java---C---6(旋转)
  8. 希尔排序+移位法(吊打交换法)
  9. 蓝桥杯JAVA省赛2013-----B------3(振兴中华)
  10. IDEA无法加载log文件