Spring Boot Security Oauth2之客户端模式及密码模式实现

示例主要内容

  • 1.多认证模式(密码模式、客户端模式)
  • 2.token存到redis支持
  • 3.资源保护
  • 4.密码模式用户及权限存到数据库
  • 5.使用说明

示例代码-github

介绍

oauth2 client credentials 客户端模式获取access_token流程

客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。

  • (A)客户端向认证服务器进行身份认证,并要求一个访问令牌。客户端发出的HTTP请求,包含以下参数:

    granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。

    scope:表示权限范围,可选项。

  • (B)认证服务器确认无误后,向客户端提供访问令牌。

oauth2 password 密码模式获取access_token流程

密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。

在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

  • (A)用户向客户端提供用户名和密码。

  • (B)客户端将用户名和密码发给认证服务器,向后者请求令牌。 客户端发出的HTTP请求,包含以下参数:

    grant_type:表示授权类型,此处的值固定为"password",必选项。

    username:表示用户名,必选项。

    password:表示用户的密码,必选项。

    scope:表示权限范围,可选项。

  • (C)认证服务器确认无误后,向客户端提供访问令牌。

Oauth2提供的默认端点(endpoints)

  • /oauth/authorize:授权端点
  • /oauth/token:令牌端点
  • /oauth/confirm_access:用户确认授权提交端点
  • /oauth/error:授权服务错误信息端点
  • /oauth/check_token:用于资源服务访问的令牌解析端点
  • /oauth/token_key:提供公有密匙的端点,如果使用JWT令牌的话

示例使用介绍

1.端模式获取access_token

http://localhost:8080/oauth/token?grant_type=client_credentials&scope=select&client_id=client_1&client_secret=123456

返回结果

{
"access_token": "67a2c8f6-bd08-4409-a0d6-6ba61a4be950",
"token_type": "bearer",
"expires_in": 41203,
"scope": "select"
}

2.密码模式获取access_token

http://localhost:8080/oauth/token?username=user&password=123456&grant_type=password&scope=select&client_id=client_2&client_secret=123456

返回结果

{
"access_token": "b3d2c131-1225-45b4-9ff5-51ec17511cee",
"token_type": "bearer",
"refresh_token": "8495d597-0560-4598-95ef-143c0855363c",
"expires_in": 42417,
"scope": "select"
}

3.刷新access_token

http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=8495d597-0560-4598-95ef-143c0855363c&client_id=client_2&client_secret=123456

返回结果

{
"access_token": "63de6c71-672f-418c-80eb-0c9abc95b67c",
"token_type": "bearer",
"refresh_token": "8495d597-0560-4598-95ef-143c0855363c",
"expires_in": 43199,
"scope": "select"
}

4.访问受保护的资源

http://localhost:8080/order/1?access_token=b3d2c131-1225-45b4-9ff5-51ec17511cee

正确返回数据

spring security oauth2代码过程

security oauth2 整合的3个核心配置类

  • 1.资源服务配置 ResourceServerConfiguration
  • 2.授权认证服务配置 AuthorizationServerConfiguration
  • 3.security 配置 SecurityConfiguration

1.pom.xml添加maven依赖

    <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> <dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.6.RELEASE</version>
</dependency> <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>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency> <dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.2</version>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> <dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.1</version>
<scope>test</scope>
</dependency>
</dependencies>

主要使用了:security、oauth2、redis、mysql、mybatis-plus等组件

2.认证授权配置AuthorizationServerConfigurerAdapter.java

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { private static final String RESOURCE_IDS = "order"; @Autowired
AuthenticationManager authenticationManager; @Autowired
RedisConnectionFactory redisConnectionFactory; @Autowired
private UserDetailsService userDetailsService; @Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception { String finalSecret = "{bcrypt}" + new BCryptPasswordEncoder().encode("123456");
//配置两个客户端,一个用于password认证一个用于client认证
clients.inMemory() //client模式
.withClient("client_1")
.resourceIds(RESOURCE_IDS)
.authorizedGrantTypes("client_credentials", "refresh_token")
.scopes("select")
.authorities("oauth2")
.secret(finalSecret) .and() //密码模式
.withClient("client_2")
.resourceIds(RESOURCE_IDS)
.authorizedGrantTypes("password", "refresh_token")
.scopes("select")
.authorities("oauth2")
.secret(finalSecret);
} /**
* 认证服务端点配置
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
//用户管理
.userDetailsService(userDetailsService)
//token存到redis
.tokenStore(new RedisTokenStore(redisConnectionFactory))
//启用oauth2管理
.authenticationManager(authenticationManager)
//接收GET和POST
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
} @Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.allowFormAuthenticationForClients();
}
}

3.资源配置ResourceServerConfig.java

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter { private static final String RESOURCE_IDS = "order"; @Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_IDS).stateless(true);
} @Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers("/order/**").authenticated(); //配置order访问控制,必须认证过后才可以访问 }
}

4.密码模式的用户及权限存到了数据库,UserDetailsServiceImpl.java


@Service
public class UserDetailsServiceImpl implements UserDetailsService { @Autowired
private UserServiceImpl userService; /**
* 实现UserDetailsService中的loadUserByUsername方法,用于加载用户数据
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.queryUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
} //用户权限列表
Collection<? extends GrantedAuthority> authorities = userService.queryUserAuthorities(user.getId()); return new AuthUser(
user.getId(),
user.getUsername(),
user.getPassword(),
true,
true,
true,
true,
authorities);
}
}

5.WebSecurityConfig配置

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
} /**
* 注入AuthenticationManager接口,启用OAuth2密码模式
*
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
AuthenticationManager manager = super.authenticationManagerBean();
return manager;
} /**
* 通过HttpSecurity实现Security的自定义过滤配置
*
* @param httpSecurity
* @throws Exception
*/
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.requestMatchers().anyRequest()
.and()
.authorizeRequests()
.antMatchers("/oauth/**").permitAll();
}
}

6.application.yml配置

server:
port: 8080 spring:
thymeleaf:
encoding: UTF-8
cache: false datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/easy_web?useSSL=false&serverTimezone=UTC
username: root
password: 123456 redis:
host: 127.0.0.1
port: 6379
password: logging.level.org.springframework.security: DEBUG

7.inital.sql数据库初始化脚本

DROP TABLE IF EXISTS `user`;
DROP TABLE IF EXISTS `role`;
DROP TABLE IF EXISTS `user_role`;
DROP TABLE IF EXISTS `role_permission`;
DROP TABLE IF EXISTS `permission`; CREATE TABLE `user` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `role` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `user_role` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`user_id` bigint(11) NOT NULL,
`role_id` bigint(11) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `role_permission` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`role_id` bigint(11) NOT NULL,
`permission_id` bigint(11) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `permission` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`description` varchar(255) NULL,
`pid` bigint(11) NOT NULL,
PRIMARY KEY (`id`)
); INSERT INTO user (id, username, password) VALUES (1,'user','{bcrypt}$2a$10$Tme77eHtXzcB8ghQUepYguJr7P7ESg0Y7XHMnk60s.kf2A.BWBD9m');
INSERT INTO user (id, username , password) VALUES (2,'admin','{bcrypt}$2a$10$Tme77eHtXzcB8ghQUepYguJr7P7ESg0Y7XHMnk60s.kf2A.BWBD9m');
INSERT INTO role (id, name) VALUES (1,'USER');
INSERT INTO role (id, name) VALUES (2,'ADMIN');
INSERT INTO permission (id, url, name, pid) VALUES (1,'/user/common','common',0);
INSERT INTO permission (id, url, name, pid) VALUES (2,'/user/admin','admin',0);
INSERT INTO user_role (user_id, role_id) VALUES (1, 1);
INSERT INTO user_role (user_id, role_id) VALUES (2, 1);
INSERT INTO user_role (user_id, role_id) VALUES (2, 2);
INSERT INTO role_permission (role_id, permission_id) VALUES (1, 1);
INSERT INTO role_permission (role_id, permission_id) VALUES (2, 1);
INSERT INTO role_permission (role_id, permission_id) VALUES (2, 2);

经过以上七个步骤,我们快速实现了Oauth2的密码模式和客户模式功能。

资料

Spring Boot Security Oauth2之客户端模式及密码模式实现的更多相关文章

  1. Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器

    概要 之前的两篇文章,讲述了Spring Security 结合 OAuth2 .JWT 的使用,这一节要求对 OAuth2.JWT 有了解,若不清楚,先移步到下面两篇提前了解下. Spring Bo ...

  2. Spring Boot Security 整合 OAuth2 设计安全API接口服务

    简介 OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版.本文重点讲解Spring Boot项目对OAuth2进行的实现,如果你对OAut ...

  3. Spring Security OAuth2 微服务认证中心自定义授权模式扩展以及常见登录认证场景下的应用实战

    一. 前言 [APP 移动端]Spring Security OAuth2 手机短信验证码模式 [微信小程序]Spring Security OAuth2 微信授权模式 [管理系统]Spring Se ...

  4. Spring Boot Security配置教程

    1.简介 在本文中,我们将了解Spring Boot对spring Security的支持. 简而言之,我们将专注于默认Security配置以及如何在需要时禁用或自定义它. 2.默认Security设 ...

  5. Spring Boot Security 整合 JWT 实现 无状态的分布式API接口

    简介 JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案.JSON Web Token 入门教程 - 阮一峰,这篇文章可以帮你了解JWT的概念.本文重点讲解Spring Boo ...

  6. Spring Boot Security JWT 整合实现前后端分离认证示例

    前面两章节我们介绍了 Spring Boot Security 快速入门 和 Spring Boot JWT 快速入门,本章节使用 JWT 和 Spring Boot Security 构件一个前后端 ...

  7. Spring Boot 与 OAuth2 官方最详细教程

    https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247484357&idx=1&sn=73e501de8591e6 ...

  8. boke练习: spring boot: security post数据时,要么关闭crst,要么添加隐藏域

    spring boot: security post数据时,要么关闭crst,要么添加隐藏域 http.csrf().disable(); 或者: <input name="${_cs ...

  9. 使用Spring Cloud Security OAuth2搭建授权服务

    阅读数:84139 前言: 本文意在抛砖引玉,帮大家将基本的环境搭起来,具体实战方案还要根据自己的业务需求进行制定.我们最终没有使用Spring Security OAuth2来搭建授权服务,而是完全 ...

随机推荐

  1. 自己实现定制自己的专属java锁,来高效规避不稳定的第三方

    java juc 包下面已经提供了很多并发锁工具供我们使用,但在日常开发中,为了各种原因我们总是会用多线程来并发处理一些问题,然而并不是所有的场景都可以使用juc 或者java本身提供的锁来方便的帮助 ...

  2. extern和static区别

    1. 声明和定义 ​ 当定义一个变量的时候,就包含了对该变量声明的过程,同时在内存张申请了一块内存空间.如果在多个文件中使用相同的变量,为了避免重复定义,就必须将声明和定义分离开来.定义是创建与名字关 ...

  3. 2. Django每日一码 之as_view() 源码

    2019-7-5  今日源码: as_view() CBV与FBV路由区别 urlpatterns = [ url(r'^publish/$', views.Publishs.as_view()), ...

  4. vue源码阅读(二)

    一 一个实例 如果简单了解过些Vue的API的话,肯定会对一下这个特别熟悉,在上一篇里,分析了Vue的核心文件core的index.js构造vue函数执行的流程. 那么下边这个则是实例化构造函数,也就 ...

  5. ES6中的解构

    数组中的解构: 输出 : 白板 幺鸡 二条 对象的解构: 输出: 老王 12 数组的结构用[];对象的解构用{}:一定要区分它是数组还是解构. 区分方法:看 它是在赋值还是在拿值,等号左边,都为解构, ...

  6. 简单的量子算法(一):Hadamard 变换、Parity Problem

    Hadamard Transform Hadamard 变换在量子逻辑门中提过,只不过那时是单量子的Hadamard门,负责把\(|1\rangle\)变成\(|-\rangle\),\(|0\ran ...

  7. python基础一整型、bool、字符串

    1整型.bool.字符串 1.整型 --数字(int) ​ 用于比较运算的 ​ 32位 -2 ** 31 ~ 2 ** 31 -1 ​ 64位 -2 ** 63 ~ 2 ** 63 -1 ​ 基础运算 ...

  8. FC游戏修改教程(hack)小白文。

    FC(NES)红白机Family Computer(简称FAMICOM)(或Nintendo Entertainment System)是任天堂公司发行的第一代家用游戏机. 修改FC游戏需要的工具有 ...

  9. 【LightOJ - 1370】Bi-shoe and Phi-shoe

    Bi-shoe and Phi-shoe Descriptions: 给出一些数字,对于每个数字找到一个欧拉函数值大于等于这个数的数,求找到的所有数的最小和. Input 输入以整数T(≤100)开始 ...

  10. 2019年7月22日 - LeetCode0004

    https://leetcode-cn.com/problems/median-of-two-sorted-arrays/submissions/ 我的解法: 我看到了那个log的要求,也第一时间想到 ...