一、介绍
1.1 Oauth2框架介绍
OAuth2是一种授权认证的登陆标准,具有安全性高,使用方便等特点,在部署微服务架构时能够有效的控制多个服务的统一登录、授权及资源保护工作。具有以下4种认证模式:
授权码模式
简化模式
密码模式
客户端模式
其中授权码模式是使用最广泛,安全性最高的认证模式;本文以Spring Security OAuth2的授权码模式为基础,搭建认证服务器、资源服务器及模拟登录的整套流程来简要介绍OAuth2的工作原理。
1.2 官网地址
1.3 程序版本
Spring Boot 版本: 2.3.3RELAESE
Spring Cloud 版本:Hoxton.SR7
MyBatis 版本:3.5.5
MySQL 数据库驱动版本:5.1.46
二、环境搭建
2.1 配置
Spring Security OAuth2完整的实现了OAuth2授权登录标准,使用时只需要配置pom文件;认证服务器访问令牌(access_token)存储在Redis中,使用前需要启动Redis
2.1.1 配置Redis
单机应用只需要在默认端口启动Redis即可
2.1.2 配置pom文件
认证服务器及资源服务器分别配置
2.1.2.1 配置认证服务器
创建Spring Web项目,同时在添加依赖的窗口添加OAuth2相关依赖
图-1
在pom文件中添加redis依赖
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.3.RELEASE
cn.toj
oauth2demo-server
0.0.1-SNAPSHOT
oauth2demo-server
Demo project for Spring Boot
1.8
Hoxton.SR7
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-oauth2
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-starter-data-redis
org.assertj
assertj-core
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
2.1.2.2 配置资源服务器
资源服务器主要访问数据库中数据,所以需要添加MySQL访问相关依赖及MyBatis依赖,同样创建Spring Web和Spring Security OAuth2项目
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.3.RELEASE
cn.toj
oauth2demo-resources
0.0.1-SNAPSHOT
oauth2demo-resources
Demo project for Spring Boot
1.8
Hoxton.SR7
3.5.5
2.1.3
5.1.46
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-oauth2
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis-spring-boot-starter.version}
org.mybatis
mybatis
${mybatis.version}
mysql
mysql-connector-java
${mysql-connector-java.version}
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
三、Demo开发演示
3.1 Demo概述
本Demo主要功能为使用授权码认证模式从资源服务器根据权限获取需要的数据,认证服务器的用户数据存储在内存中,生成的授权码存储在Redis中,资源服务器的数据存储在数据库中,客户端可根据权限进行获取。
3.1.1 认证服务器搭建
认证服务器的application.properties文件比较简单,主要规定了项目的名称和运行端口
# 项目名称
spring.application.name=oauth2demo-server
# 运行端口
server.port=8001
AuthorizationServerConfiguration类主要功能是配置客户端,必须继承AuthorizationServerConfigurerAdapter并重写configure方法,将配置写入内存;其中密码需要进行加密,本Demo使用BCryptPasswordEncoder对象将字符串转化为密码,实际使用可使用MD5等其他加密方式。
package cn.toj.oauth2demoserver.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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;
/**
* @author Carlos
* @description
* @Date 2020/8/19
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
public BCryptPasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 配置客户端
clients
// 使用内存设置
.inMemory()
// client_id
.withClient("client")
// client_secret
.secret(passwordEncoder.encode("secret"))
// 授权类型
.authorizedGrantTypes("authorization_code")
// 授权范围
.scopes("app")
// 注册回调地址
.redirectUris("https://www.baidu.com");
}
}
WebSecurityConfiguration类继承了WebSecurityConfigurerAdapter类并重写了configure方法在内存存入用户信息及角色,密码仍进行加密。
package cn.toj.oauth2demoserver.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author Carlos
* @description
* @Date 2020/8/19
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true, securedEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("123456")).roles("ADMIN")
.and()
.withUser("user").password(passwordEncoder().encode("123456")).roles("USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/oauth/check_token");
}
}
认证服务器配置完毕
3.1.2 资源服务器搭建
资源服务器的application.properties文件配置了数据库连接相关配置,并添加了认证服务器地址
# 运行端口
server.port=8002
# 默认地址
server.servlet.context-path=/contents
# 配置数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/user?characterEncoding=utf-8&useSSL=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
# MyBatis配置
mybatis.type-aliases-package=cn.toj.druiddemo.domain
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
# OAuth2客户端设置
security.oauth2.client.client-id=client
security.oauth2.client.client-secret=secret
security.oauth2.client.access-token-uri=http://localhot:8001/oauth/token
security.oauth2.client.user-authorization-uri=http://localhost:8001/oauth/authorize
security.oauth2.resource.token-info-uri=http://localhost:8001/oauth/check_token
主要功能是对外报录url获取数据库表中的所有用户信息,如果不使用Spring Security OAuth2资源服务器可以直接被外界访问,不安全,添加了ResourcesServerConfiguration类进行拦截,规定了只用“ADMIN”角色可以访问,需要认证服务器进行授权
package cn.toj.oauth2demoresources.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
/**
* @author Carlos
* @description
* @Date 2020/8/20
*/
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class ResourcesServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").hasAnyRole("ADMIN");
}
}
3.2 Demo授权码模式登录演示
3.2.1 直接访问资源服务
浏览器直接访问http://localhost:8002/contents因为没有获得授权,无法获得数据,浏览器返回
Full authentication is required to access this resourceunauthorized
即“要获得此资源的未经授权,必须进行完全身份验证”,拦截成功。
3.2.2 通过认证服务器获得授权码访问资源
想从资源服务器获得数据,需要从认证服务器中获得授权码和权限,下面结合流程图模拟整个认证授权流程。
图-2
3.2.2.1 请求认证服务器获取授权码
在浏览器中输入[http://localhost:8001/oauth/authorize?client_id=client&response_type=code](http://localhost:8001/oauth/authorize?client_id=client&response_type=code)传入client_Id及返回code类型的码,系统自动跳转到登录页面,输入用户信息
图-3
在确认权限界面选择权限,并认证
图-4
3.2.2.2 认证服务器返回授权码
认证成功后浏览器自动跳转到之前设置的页面并携带授权码
图-5
3.2.2.3 客户端请求真正服务器请求访问令牌
使用postman传入获得的授权码和授权方式
图-6
3.2.2.4 认证服务器传回访问令牌信息
点击send后,从认证服务器发来访问令牌
{
"access_token": "6373d419-36c4-4352-99c8-b89cb6de7582",
"token_type": "bearer",
"expires_in": 43199,
"scope": "app"
}
3.2.2.5 使用获得的访问令牌向资源服务器请求数据
使用postman向资源服务器请求数据,传入刚获得的访问令牌
图-7
3.2.2.6 认证服务器和资源服务器通信
资源服务器通过在properties配置的地址与认证服务器通信,确认令牌的使用权限,决定客户端是否可以获得想获得的数据
3.2.2.7 资源服务器向客户端发送数据
资源服务器确认客户端有访问权限后,向客户端发送数据,postman接收到数据
图-8
以上就是使用授权码认证模式进行资源获取的完整流程,有兴趣的话可以试一下在第一步使用“user”账号(有USER权限,没有ADMIN权限)向资源服务器请求数据是否可以成功。
3.3 Demo下载地址
使用Git下载项目的命令:
git clone https://github.com/diyzhang/42j122-oauth2demo.git