Spring Security 实现OAuth2.0实现授权服务--基础版

   最近想学习以下OAuth2.0 ,就次机会学一下Spring Security ,当然我是借鉴了别人的文章完成的,其中遇到一些问题,但还是做一个记录。一个是想加深一下印象,一个是想以后翻起来回忆的快一点,我借鉴的文章路径如下:

https://www.cnblogs.com/xugf/p/10720659.html

首先捋一下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 ,详情可以参考 https://www.cnblogs.com/xugf/p/10720659.html

然后根据得到的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

进入登陆界面:

 

输入用户名和密码后

还是以下这样:

 

这里我就不明白了 ,留下一个疑点 以后在讨论

 

谢谢 这篇博文的作者

https://www.cnblogs.com/xugf/p/10720659.html

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值