最近想学习以下OAuth2.0 ,就次机会学一下Spring Security ,当然我是借鉴了别人的文章完成的,其中遇到一些问题,但还是做一个记录。一个是想加深一下印象,一个是想以后翻起来回忆的快一点,我借鉴的文章路径如下:
首先捋一下OAuth2.0 的知识点
一、OAuth2.0协议
1、OAuth2.0概述
OAuth2.0是一个关于授权的开放网络协议。
该协议在第三方应用与服务提供平台之间设置了一个授权层。第三方应用需要服务资源时,并不是直接使用用户帐号密码登录服务提供平台,而是通过服务提供平台的授权层获取token令牌,用户可以在授权时指定token的权限范围和有效期。第三方应用获取到token以后,才可以访问用户资源。
OAuth 2.0定义了四种授权方式:
- 授权码模式(authorization code):功能最完整、流程最严密的授权模式。特点是通过第三方应用的后台服务器,与服务提供平台的认证服务器进行互动获取资源。
- 简化模式(implicit):不通过第三方应用服务器,直接在浏览器中向认证服务器申请token令牌,跳过了授权码这个步骤。所有步骤在浏览器中完成,token对用户可见,且第三方应用不需要认证。
- 密码模式(resource owner password credentials):用户向第三方应用提供自己的用户名和密码。第三方应用使用这些信息,向服务提供平台索要授权。在这种模式中,用户必须把自己的密码给第三方应用,但是第三方应用不得储存密码。这通常用在用户对第三方应用高度信任的情况下,比如第三方应用是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。
- 客户端模式(client credentials):指第三方应用以自己的名义,而不是以用户的名义,向服务提供平台进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向第三方应用注册,第三方应用以自己的名义要求服务提供平台提供服务,其实不存在授权问题。
2、授权码模式
假设有X用户、A系统、B系统,X是A系统中的用户,B系统需要访问A系统获取X用户的信息。
- B系统中放置向A系统申请授权的入口;
- X用户点击进入A系统授权页,如果未登录需要登录;
- X用户允许授权给B系统;
- A系统重定向到B系统,并携带authorization_code授权码;
- B系统使用authorization_code授权码到A系统获取token令牌;
- B系统可以使用token令牌到A系统获取用户资源。
再举个授权码模式的例子:某网站QQ快速登录、账号绑定。
- 用户点击网站的QQ登录图标
- 页面跳转到QQ提供的授权页,如果PC上没有登录QQ账号,需要登录
- 用户允许授权
- 重定向到网站回调地址,携带授权码authorization_code
- 网站使用授权码获取token
- 使用token拉取QQ账号信息
- 使用QQ账号信息登录、账号绑定等
二、Spring Security概述
Spring Security是一个用于快速实现Web应用安全、认证的框架,可以快速和Spring Boot整合。
开发者可以编写配置类继承WebSecurityConfigurerAdapter类,重写config方法自定义登录页面、登录失败逻辑、权限不足逻辑等,并且可以编写Filter实现更加复杂的图片验证码、短信验证码功能。
Spring Security也可以快速实现OAuth2.0授权服务器和资源服务器。在一个Spring Boot应用中,可以使用@EnableAuthorizationServer注解实现授权服务器,使用@EnableResourceServer注解实现资源服务器。
三。下面我们就来使用具体案例实现一个简单的demo
1.新建一个SpringBoot父工程
创建过程具体不再赘述
创建后工程的目录如下,是一个最简单的Springboot项目
2.接下来在父工程下面新建一个Module (oauth-client)
具体创建过程这里也不再赘述,pom文件中之引入spring-boot-starter-web的依赖
项目结构如下:
新建一个DemoController,代码如下:
package com.taoj.demo.oauthclient.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("say")
public String sayHello(){
return "I say I Love You";
}
}
application.properties文件中什么也没写,所以端口就是默认的8080
启动这个工程,访问 http://localhost:8080/say 如下所以:
这里不再赘述一切都很简单
接下来我们要新建一个 Oauth-Server的工程
同样的新建一个子工程 oauth-server
pom文件中引入这些依赖
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- OAuth2.0 -->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>compile</scope>
</dependency>
引入之后pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.taoj.demo</groupId>
<artifactId>oauth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>oauth-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- OAuth2.0 -->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
待依赖都引入后,我们在这个工程下新建一个Controller
package com.taoj.demo.oauthserver.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("love")
public String sayLove(){
return "sayLove";
}
}
application.properties文件如下:
server.port=7000
# Security
spring.security.user.name=admin
spring.security.user.password=123456
# Security OAuth2 Client
security.oauth2.client.client-id=net5ijy
security.oauth2.client.client-secret=123456
这里我们新建了一个用户名和密码,并且也规定了一个客户端的id为net5ijy 和secret为123456
接下来我们启动oauth-server
访问 http://localhost:7000/love
我们看到会跳转到一个用户名密码认证界面:
我们输入一个刚才设置的用户名密码 adamin/123456
点击登陆 账号密码 认证成功 就会出现下面的界面
说明一个简单的Spring Security OAuth例子已经完成,接下来我们来看看是怎么工作的
我们 先清一下缓存,访问
http://localhost:7000/oauth/authorize?response_type=code&client_id=net5ijy&redirect_uri=http://localhost:8080&scope=all
也会跳转到登录界面:
我们输入用户名密码 admin/123456后
跳转到了这个界面 ,我们知道
http://localhost:7000/oauth/authorize?response_type=code&client_id=net5ijy&redirect_uri=http://localhost:8080&scope=all
这个url中 参数表示如下:
参数
response_type | code |
client_id | 根据实际的client-id填写,此处写net5ijy |
redirect_uri | 生成code后的回调地址,http://localhost:8080 |
scope | 权限范围 |
其中redirect_url是回调页面,会带上code ,详情可以参考
然后根据得到的code 在获取access_token 得到access_token后 ,有可以根据这个access_token获取资源,这就是基本的OAuth2.0协议,但是我们上述的这个例子中很遗憾没有得到code,是因为我们这是一个SpringBoot项目,如果直接访问 http://localhost:8080 不会出现tomcat猫界面,所以没有获取到code,那之后我把redirect_url换成一个能接收code的请求,也是不行,这里就有问题了,时间不早了,以后再研究吧,哎。。。。
我改造了一个oauth-client工程中Controller的内容:
package com.taoj.demo.oauthclient.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("say")
public String sayHello(@RequestParam(required = false) String code){
String str = code;
System.out.println(code);
return "I say I Love You";
}
}
之后我们访问:
http://localhost:7000/oauth/authorize?response_type=code&client_id=net5ijy&redirect_uri=http://localhost:8080/say&scope=all
进入登陆界面:
输入用户名和密码后
还是以下这样:
这里我就不明白了 ,留下一个疑点 以后在讨论