SpringBoot安全管理之OAuth2框架怎么使用
OAuth3简介
OAuth 是一个开放标准,该标准允许用户让第三方应用访问该用户在某一网站上存储的私密资源(如头像、照片、视频等),而在这个过程中无须将用户名和密码提供给第三方应用。
访问存储在特定服务提供者中的数据,采用的是使用令牌而非用户名和密码的方式实现。每一个令牌授权一个特定的网站在特定的时间段内访问特定的资源。
OAuth使用户可以授权第三方网站灵活地访问存储在另一些资源服务器上的特定信息,而不是所有信息。例如,用户想通过 QQ 登录知乎,这时知乎就是一个第三方应用,知乎要访问用户的一些基本信息就需要得到用户的授权,如果用户把自己的 QQ 用户名和密码告诉知乎,那么知乎就能访问用户的所有数据,并且只有用户修改密码才能收回权限,这种授权方式安全隐患很大,如果使用 OAuth ,就能很好的解决这一问题。
采用令牌的方式可以让用户灵活的对第三方应用授权或者收回权限。OAuth 2 是 OAuth 协议的下一版,不过与 OAuth 1.0 不具备向下兼容性。
OAuth 2 关注客户端开发者的简易型,同时为Web应用、桌面应用,移动设备、起居室设备提供专门的认证流程。传统的 Web 开发登录认证一般都是基于 Session 的,但是前后端分离的架构中继续使用 Session 会有许多不便,因为移动端(Android、IOS、微信小程序等)要么不支持 Cookie(微信小程序),要么使用非常不便,对于这些问题,使用 OAuth 2 认证都能解决。
OAuth3角色
先了解 OAuth 2 中几个基本的角色
资源所有者:即用户,具有头像、照片、视频等资源
客户端:即第三方应用
授权服务器:用来验证用户提供的信息是否正确,并返回一个令牌给第三方应用
资源服务器:提供给用户资源的服务器,例如头像、照片、视频等资源
一般来说,授权服务器和资源服务器可以是同一台服务器。
OAuth3授权流程
步骤01:客户端(第三方应用)向用户请求授权。
当用户在服务授权页面上单击同意授权按钮后,服务端会向客户端返回一个授权许可凭证。
步骤03:客户端拿着授权许可证去授权服务器申请令牌。
步骤04:授权服务器验证信息无误后,发放令牌给客户端。
步骤05:客户端拿着令牌去资源服务器访问资源。
步骤06:资源服务器验证令牌无误后开放资源。
授权模式
OAuth 协议的授权模式共分为 4 种,如下
授权码授权模式是授权方式中功能最齐全、流程最严谨的,其授权码(authorization code)是关键。这种模式的特点在于客户端的服务器与授权服务器进行交互,国内常见的第三方平台登录功能基本都采用了这种方式
简化模式:简化模式不需要客户端服务器参与,直接在浏览器中向授权服务器申请令牌,一般若是纯静态页面,则可以采用这种方式
在密码模式下,用户直接向客户端提供自己的用户名和密码,客户端则使用这些信息向授权服务器请求访问令牌。用户需要了解客户端的高度信息,例如客户端应用和服务提供商是否同一家公司
在客户端模式下,服务提供者向客户端授权而非特定用户。严格来说,客户端模式并不能算作 OAuth 协议要解决的问题的一种解决方案,但是,对于开发者而言,在一些前后端分离应用或者为移动端提供的认证授权服务器上使用这种模式还是非常方便的
4 种模式各有千秋,分别适用于不同的开发场景,开发者根据实际情况进行选择
实践
此处介绍的是在前后端分离应用(或为移动端、微信小程序等)提供的认证服务器中如何搭建 OAuth 服务,因此主要介绍密码模式。
1. 创建项目添加依赖
创建 Spring Boot Web 项目,添加如下依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth3</artifactId> <version>2.3.3.RELEASE</version> </dependency>
由于 Spring Boot 中的 OAuth 协议是在 Spring Security 的基础上完成的,因此首先要添加 Spring Security 依赖,要用到 OAuth 2,因此添加 OAuth 2 相关依赖,令牌可以存储在 Redis 缓存服务器上,同时 Redis 具有过期等功能,很适合令牌的存储,因此也加入 Redis 依赖。
配置 application.properties
spring.redis.database=0
spring.redis.host=ip地址
spring.redis.port=6379
spring.redis.password=root
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
2. 配置授权服务器
授权服务器和资源服务器可以是同一台服务器,也可以是不同服务器,此处假设是同一台服务器,通过不同的配置分别开启授权服务器和资源服务器,首先是授权服务器:
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired AuthenticationManager authenticationManager; @Autowired RedisConnectionFactory redisConnectionFactory; @Autowired UserDetailsService userDetailsService; @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("password") .authorizedGrantTypes("password", "refresh_token") .accessTokenValiditySeconds(1800) .resourceIds("rid") .scopes("all") .secret("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory)) .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.allowFormAuthenticationForClients(); } }
代码解释:
自定义类继承自 AuthorizationServerConfigurerAdapter ,完成对授权服务器的配置,然后通过 @EnableAuthorizationServer 注解开启授权服务器
注入 AuthenticationManager 用来支持 password 模式
注入 RedisConnectionFactory 用来完成 Redis 缓存,将令牌信息储存到 Redis 缓存中
注入 UserDetailsService 该对象为刷新 token 提供支持
在 configure(ClientDetailsServiceConfigurer clients) 方法中配置 password 授权模式,authorizedGrantTypes 表示 OAuth 2 中的授权模式为 password 和 refresh_token 两种,在标准的 OAuth 2 协议中,授权模式并不包括 refresh_token ,但是在 Spring Security 的实现中将其归为一种,因此如果要实现 access_token 的刷新,就需要添加这样一种授权模式;accessTokenValiditySeconds 方法配置了 access_token 的过期时间;resourceIds 配置了资源 id;secret 方法配置了加密后的密码,明文是 123
configure(AuthorizationServerEndpointsConfigurer endpoints) 方法配置了令牌的存储,AuthenticationManager 和 UserDetailsService 主要用于支持 password 模式以及令牌的刷新
configure(AuthorizationServerSecurityConfigurer security) 方法配置表示支持 client_id 和 client_secret 做登录认证
3. 配置资源服务器
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId("rid").stateless(true); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("admin") .antMatchers("/user/**").hasRole("user") .anyRequest().authenticated(); } }
代码解释:
自定义类继承自 ResourceServerConfigurerAdapter ,并添加 @EnableResourceServer 注解开启资源服务器配置
resources.resourceId(“rid”).stateless(true); 配置资源 id,这里的资源 id 和授权服务器中的资源 id 一直,然后设置这些资源仅基于令牌认证
configure(HttpSecurity http) 方法配置 HttpSecurity
4. 配置 Security
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean @Override protected UserDetailsService userDetailsService() { return super.userDetailsService(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin") .password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq") .roles("admin") .and() .withUser("sang") .password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq") .roles("user"); } @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/oauth/**").authorizeRequests() .antMatchers("/oauth/**").permitAll() .and().csrf().disable(); } }
这里两个 Bean 将注入授权服务器配置类中使用,另外,这里的 HttpSecurity 配置主要是配置 /oauth/** 模式的 URL ,这一类的请求直接放行。在 Spring Security 配置和资源服务器配置中,一共涉及两个 HttpSecurity ,其中 Spring Security 中的配置优先级高于资源服务器中的配置,即请求地址先经过 Spring Security 的 HttpSecurity ,再经过资源服务器的 HttpSecurity。
5. 验证测试
首先创建三个简单的请求地址
@RestController public class HelloController { @GetMapping("/admin/hello") public String admin() { return "Hello admin!"; } @GetMapping("/user/hello") public String user() { return "Hello user!"; } @GetMapping("/hello") public String hello() { return "hello"; } }
根据前文的配置,要请求这三个地址,分别需要 admin 角色、user 角色以及登录后访问。
所有都配置完成后,启动 Redis 服务器,再启动 Spring Boot 项目,首先发送一个 POST 请求获取 token,请求地址如下(注意这里是一个 POST 请求,为了显示方便,将参数写在地址栏中):http://localhost:8080/oauth/token?username=sang&password=123&grant_type=password&client_id=password&scope=all&client_secret=123
请求地址中包含的参数有用户名、密码、授权模式、客户端 id 、scope 以及客户端密码,基本就是授权服务器中所配置的数据,请求结果如图
其中 access_token 是获取其它资源时要用的令牌,refresh_token 用来刷新令牌,expires_in 表示 access_token 过期时间,当 access_token 过期后,使用 refresh_token 重新获取新的 access_token (前提是 refresh_token 未过期),请求地址(注意也是POST请求):http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=693b0e36-4515-442a-8c5d-90bade3c74d2&client_id=password&client_secret=123
获取新的 access_token 时需要携带上 refresh_token ,同事授权模式设置为 refresh_token ,在获取的结果中 access_token 会变化,同时 access_token 有效期也会变化,如图
接下来访问所有资源,携带上 access_token 参数即可,例如 /user/hello 接口:http://localhost:8080/user/hello?access_token=0497e4bc-df37-460e-8755-b813b9dbf36a,访问结果如图
如果非法访问一个资源,例如 sang 用户访问 /admin/hello 接口,结果如图
到此,一个 password 模式的 OAuth 认证体系就搭建成功了。
OAuth 中的认证模式有 4 中,开发者需要结合自己开发的实际情况选择其中一种,此处介绍的是在前后端分离应用中常用的 password 模式,其它的授权模式也都有自己的使用场景。
整体来讲,Spring Security OAuth 2 的使用还是较复杂的,配置也比较繁琐,如果开发者的应用场景比较简单,完全可以按照此处介绍的授权流程自己搭建 OAuth 2 认证体系。
以上是SpringBoot安全管理之OAuth2框架怎么使用的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Jasypt介绍Jasypt是一个java库,它允许开发员以最少的努力为他/她的项目添加基本的加密功能,并且不需要对加密工作原理有深入的了解用于单向和双向加密的高安全性、基于标准的加密技术。加密密码,文本,数字,二进制文件...适合集成到基于Spring的应用程序中,开放API,用于任何JCE提供程序...添加如下依赖:com.github.ulisesbocchiojasypt-spring-boot-starter2.1.1Jasypt好处保护我们的系统安全,即使代码泄露,也可以保证数据源的

使用场景1、下单成功,30分钟未支付。支付超时,自动取消订单2、订单签收,签收后7天未进行评价。订单超时未评价,系统默认好评3、下单成功,商家5分钟未接单,订单取消4、配送超时,推送短信提醒……对于延时比较长的场景、实时性不高的场景,我们可以采用任务调度的方式定时轮询处理。如:xxl-job今天我们采

一、Redis实现分布式锁原理为什么需要分布式锁在聊分布式锁之前,有必要先解释一下,为什么需要分布式锁。与分布式锁相对就的是单机锁,我们在写多线程程序时,避免同时操作一个共享变量产生数据问题,通常会使用一把锁来互斥以保证共享变量的正确性,其使用范围是在同一个进程中。如果换做是多个进程,需要同时操作一个共享资源,如何互斥呢?现在的业务应用通常是微服务架构,这也意味着一个应用会部署多个进程,多个进程如果需要修改MySQL中的同一行记录,为了避免操作乱序导致脏数据,此时就需要引入分布式锁了。想要实现分

springboot读取文件,打成jar包后访问不到最新开发出现一种情况,springboot打成jar包后读取不到文件,原因是打包之后,文件的虚拟路径是无效的,只能通过流去读取。文件在resources下publicvoidtest(){Listnames=newArrayList();InputStreamReaderread=null;try{ClassPathResourceresource=newClassPathResource("name.txt");Input

在Springboot+Mybatis-plus不使用SQL语句进行多表添加操作我所遇到的问题准备工作在测试环境下模拟思维分解一下:创建出一个带有参数的BrandDTO对象模拟对后台传递参数我所遇到的问题我们都知道,在我们使用Mybatis-plus中进行多表操作是极其困难的,如果你不使用Mybatis-plus-join这一类的工具,你只能去配置对应的Mapper.xml文件,配置又臭又长的ResultMap,然后再去写对应的sql语句,这种方法虽然看上去很麻烦,但具有很高的灵活性,可以让我们

SpringBoot和SpringMVC都是Java开发中常用的框架,但它们之间有一些明显的差异。本文将探究这两个框架的特点和用途,并对它们的差异进行比较。首先,我们来了解一下SpringBoot。SpringBoot是由Pivotal团队开发的,它旨在简化基于Spring框架的应用程序的创建和部署。它提供了一种快速、轻量级的方式来构建独立的、可执行

1、自定义RedisTemplate1.1、RedisAPI默认序列化机制基于API的Redis缓存实现是使用RedisTemplate模板进行数据缓存操作的,这里打开RedisTemplate类,查看该类的源码信息publicclassRedisTemplateextendsRedisAccessorimplementsRedisOperations,BeanClassLoaderAware{//声明了key、value的各种序列化方式,初始值为空@NullableprivateRedisSe

本文来写个详细的例子来说下dubbo+nacos+Spring Boot开发实战。本文不会讲述太多的理论的知识,会写一个最简单的例子来说明dubbo如何与nacos整合,快速搭建开发环境。
