前言
想了半天,其实没有什么前言,这篇文章就是讲基于oauth2的密码模式实现spring boot程序的基本授权和保护
,带大家跑一下流程,帮助大家认识了解一下这个东西。
准备
spring boot 的版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.15.RELEASE</version>
<relativePath/>
</parent>
开始
1. 添加依赖
主要就是添加spring security oauth2的依赖,其他的依赖就根据自己的业务,需要什么添加什么,爱咋咋地
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
2. 编写配置
在这块呢,需要对oauth 2标准有一定的了解。如果没有了解过的话去网上看看资料,很简单的。那我们需要配置的是授权服务器、资源服务器和客户端。虽然一般对于oauth的教程里面都会说,授权服务器和资源服务器只是概念上的区别,实际上可以放在同一台机器上,事实上确实是如此,但是我觉得大家初学oauth 2的话还是把它分开理解。
我们来举个例子搭建一下概念。现在前后端分离很普遍,我们就以这个举例子。公司需要做一个项目,前端项目和后端项目分离,假定需要保护的资源就是api接口别无其他,那对应oauth 2里面的角色就是下面这种:
资源服务器
:提供api接口的服务器
资源所有者
:用户,资源是用户的但只是放在你的服务器上,不要会错意好吧,毕竟用户的账号密码只有他知道
第三方客户端
:前端项目,用户通过前端项目访问自己的资源(api接口)
认证服务器
:想象成一台单独的服务器,专门来认证,通过就发token,不通过就挡回去
整个流程呢,大家看过oauth标准的一些资料以后也都心里有数了,我就只文字上的描述一下。资源所有者(用户)通过第三方客户端(前端界面)向认证服务器发认证请求,认证服务器验证通过后发一个token给第三方客户端,然后第三方客户端拿着token就去找资源服务器(后端项目)去换资源(调用api接口)。
想要认证服务器给自己token的话,有四种方法大家也都了解了,这篇文章只讲密码模式,其他三种模式呢,后续再写。现在我们开始写配置了,大家可以在项目里面单独建立一个新包,专门用来配置oauth 2,也可以新建一个项目或模块再引入到业务项目中也可以,大家自己决定,爱咋咋地。
- 认证服务器配置
新建一个类
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig {
}
EnableAuthorizationServer
注解让这个项目成为了认证服务器,Configuration
注解表明了这个类里面写的东西是一些配置,需要高冷的spring看一眼并照做。
就这样,认证服务器就搭好了。
- 资源服务器
新建一个类
@Configuration
@EnableResourceServer
public class ResourceServerConfig {
}
和认证服务器一毛一样,只是EnableResourceServer
注解让这个项目成为了资源服务器。
资源服务器搭好了。
说了你可能不信,在正常情况下,现在你的项目已经被spring security oauth2掌管了,现在你去访问你的api会被oauth 2怼回来,如下显示
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
方才我说的是正常情况,如果你的IDE控制台打印了下面这三个配置信息就属于正常情况了,否则就不正常,自己重新看一下上面那两个类,总共六行代码,我写的比较漂亮算十行。这六行代码除了类名你爱咋咋地,其他的都和我的保持一致、spring boot版本再一致应该就没问题了,如果还有问题,留言给我。
Using default security password: 433e73a0-c8c4-4733-a812-e4eb71103122
...
security.oauth2.client.client-id = 6b620856-fc0e-4aca-b2a2-c2fce49fb954
security.oauth2.client.client-secret = 7dc2044b-6872-40f6-b80e-78673444d158
3. 获取token,访问资源
我们使用一些工具来获取token,像postman
、restlet client插件
等等。具体流程就是带上指定的参数,POST方式访问${项目根地址}/oauth/token
就可以拿到token了。在获取token之前呢,很多教程直接扒拉一下参数,然后用curl或者其他工具咣当一下就搞定了,这里从我的当初学艺的经验来看,我觉得有个事儿需要掰扯一下,就是http basic认证。
- http basic认证
大家用Chrome打开刚才我说获取token那个连接,我的项目根路径就是http://localhost:8080
,我就访问http://localhost:8080/oauth/token
,会得到一个弹窗像这样
这个弹窗就是http basic认证。关于http basic的资料网上也有很多,我这里说一下待会我们会用到的知识,就是我们在刚才那个弹窗中输入用户名和密码点击登录后,浏览器会帮我们输入的用户名和密码做一个Base 64位编码,并将结果处理后添加到请求头中再发送出去。怎么编码的呢,就是把我们输入的用户名和密码按照username:password
的格式组装成字符串,例如用户名为zhangsan
密码为123456
组装成zhangsan:123456
,把这个字符串做Base 64位编码,得到一个字符串xxxxxx
,之后在这个字符串前面添加一个前缀Basic
得到Basic xxxxxx
,最后把得到的字符串添加到请求头Authorization中。知道了浏览器会帮我们做什么之后,我们自己把用户名和密码组织好再编码并处理之后添加到请求头Authorization中,这样我们发送请求的时候就可以直接通过http basic验证,而不会看到弹窗要求我们输入信息从而使我们获取token变得一气呵成。
讲清楚了如何通过http basic那我们获取token的过程应该不会有啥疑惑的了,让我们开始吧。我使用的是Chrome的插件restlet client
,你们会用啥用啥,不要求。打开插件后注册登录就可以使用了,我这里不演示了。
-
新建一个POST请求
-
输入网址和参数
关于参数我们看一下官网上的说明
这四个参数中,grant_type
和username
现在是固定的,grant_type
写password是代表使用密码模式,username
写user是spring security默认的,之后可以改。password
在控制台上可以找到,Using default security password: 433e73a0-c8c4-4733-a812-e4eb71103122
像这样的。scope
现在可以任意填,这个参数是管第三方客户端
的权限的,如果指定某些资源需要指定的scope
才可以访问的话,不具有该scope
的第三方客户端
就不能访问。 http basic认证
在这个环节,可以用工具提供的功能生成,也可以自己按照上面说的方法生成然后自行添加到header里面。
-
使用工具提供的功能
点击以后弹出
输入用户名密码后点击set生成即可。和上面参数中的username和password有所区别就是,上面的username和password是我们数据库中的用户数据(当然现阶段由spring给我们默认生成),这里的username和password是控制台中打印的client-id和client-secret(我们后面也可以通过配置指定)。这里是表明哪个客户端在请求授权,上面参数中是表明哪个用户在请求授权。
- 自己生成
用js或者java都可以轻松的加密和解密Base64数据,把client-id和client-secret按照规则写成client-id:client-secret
,Base64加密,然后加上前缀得到Basic xxxxxx
,注意Basic
和加密数据用一个空格隔开,最后放到header里面,key值为Authorization
是固定不能变的。
-
发送请求
这样就拿到access_token了
- 访问api接口
拿到token之后呢,我们就可以访问接口了。访问的方式有两种,第一种就是参数中传入access_token
,第二种就是在请求头Authorization中放入token的值,但是要注意格式。- 参数中传入
参数里面放入access_token
访问api接口即可 - 请求头
上面我们最终获取到token的时候,我们同时得到了一个token_typebearer
是吧,那我们就像通过http basic认证一样,在请求头Authorization中放入token_type access_token
格式的字符串,我这里就写bearer 07a06a24-d3c7-48bf-8a65-5dd315ab6eba
,写好之后发送请求即可
- 参数中传入
到此呢我们就完成了token的获取和资源的访问。
4. 遗留的问题和后记
文章中我遗留了一些问题,像如何不使用spring给我们默认的那个用户名和密码而使用我们数据库的用户、自己配置client-id和client-secret。这两个问题,你们可以自己去摸索一下,我下次讲,我想想怎么和你讲你们更好理解。
回想我当初学这个的时候,在网上看了好多文章,很多入门级的教程一贴代码就把一些配置(很基础的配置)也带上了,虽然有些前辈也在代码里面写了一些注释,但是我总觉得我不清楚为什么这么写就照抄心里很是不踏实。我写这篇文章呢,讲的东西很简单,但是我想让对于spring security oauth2零基础的同学们学到一点就知道是怎么回事。不清楚的问题给我留言,我会完善。
东西不多,但是我想讲清楚,就是这么回事。
拜拜。。。