SpringSecurity结合OAuth2实现第三方授权
一 OAuth2第三方登录架构
1.1 授权码模式架构图
image-20210226091245385.png流程
【A服务客户端】需要用到【B服务资源服务】中的资源
- 第一步:【A服务客户端】将用户自动导航到【B服务认证服务】,这一步用户需要提供一个回调地址,以备 【B服务认证服务】返回授权码使用。
- 第二步:用户点击授权按钮表示让【A服务客户端】使用【B服务资源服务】,这一步需要用户登录B服务,也就是说用户要事先具有B服务的使用权限。
- 第三步:【B服务认证服务】生成授权码,授权码将通过第一步提供的回调地址,返回给【A服务客户端】。 注意这个授权码并非通行【B服务资源服务】的通行凭证。
- 第四步:【A服务认证服务】携带上一步得到的授权码向【B服务认证服务】发送请求,获取通行凭证token。
- 第五步:【B服务认证服务】给【A服务认证服务】返回令牌token和更新令牌refresh token。
使用场景
授权码模式是OAuth2中最安全最完善的一种模式,应用场景最广泛,可以实现服务之间的调用,常见的微信,QQ等第三方登录也可采用这种方式实现。
二 环境准备
2.1 构建基于角色的表格
/*
SQLyog Ultimate v12.08 (64 bit)
MySQL - 8.0.16 : Database - security_authority
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Table structure for table `sys_permission` */
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
`permission_NAME` varchar(30) DEFAULT NULL COMMENT '菜单名称',
`permission_url` varchar(100) DEFAULT NULL COMMENT '菜单地址',
`parent_id` int(11) NOT NULL DEFAULT '0' COMMENT '父菜单id',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `sys_permission` */
/*Table structure for table `sys_role` */
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
`ROLE_NAME` varchar(30) DEFAULT NULL COMMENT '角色名称',
`ROLE_DESC` varchar(60) DEFAULT NULL COMMENT '角色描述',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*Data for the table `sys_role` */
/*Table structure for table `sys_role_permission` */
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`RID` int(11) NOT NULL COMMENT '角色编号',
`PID` int(11) NOT NULL COMMENT '权限编号',
PRIMARY KEY (`RID`,`PID`),
KEY `FK_Reference_12` (`PID`),
CONSTRAINT `FK_Reference_11` FOREIGN KEY (`RID`) REFERENCES `sys_role` (`ID`),
CONSTRAINT `FK_Reference_12` FOREIGN KEY (`PID`) REFERENCES `sys_permission` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `sys_role_permission` */
/*Table structure for table `sys_user` */
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`password` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
`status` int(1) DEFAULT '1' COMMENT '1开启0关闭',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*Data for the table `sys_user` */
/*Table structure for table `sys_user_role` */
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`UID` int(11) NOT NULL COMMENT '用户编号',
`RID` int(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (`UID`,`RID`),
KEY `FK_Reference_10` (`RID`),
CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `sys_role` (`ID`),
CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `sys_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `sys_user_role` */
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
2.2 在MySQL的表中添加几组数据用于测试
说明:
-
用户:xiaoming
密码:199748
拥有的角色:ROLE_USER,ROLE_PRODUCT
-
用户:xiaoma
密码:199748
拥有的角色:ROLE_USER,ROLE_ORDER
# sys_user表 password使用加密的方式存储 两者的密码明文为 199748
+----+----------+--------------------------------------------------------------+--------+
| id | username | password | status |
+----+----------+--------------------------------------------------------------+--------+
| 4 | xiaoming | $2a$10$9fSu8H/o/qKhRYm8N3IrGePdu5Kj3QNujaW5whHGyoi8ta0Bj4SSG | 1 |
| 5 | xiaoma | $2a$10$NJkRs/2AoD1iHlLNe4LwPu8M1ZvmVp4lsCD0QEqCoaRg1Jn2AG2hu | 1 |
+----+----------+--------------------------------------------------------------+--------+
# sys_role表
+----+--------------+--------------+
| ID | ROLE_NAME | ROLE_DESC |
+----+--------------+--------------+
| 6 | ROLE_USER | Basic Role |
| 7 | ROLE_PRODUCT | Product Role |
| 8 | ROLE_ORDER | Order Role |
| 9 | ROLE_ADMIN | Root |
+----+--------------+--------------+
# sys_user_role表
+-----+-----+
| UID | RID |
+-----+-----+
| 4 | 6 |
| 5 | 6 |
| 4 | 7 |
| 5 | 8 |
+-----+-----+
2.3 创建OAuth2.0表
/*
SQLyog Ultimate v12.08 (64 bit)
MySQL - 8.0.16 : Database - security_authority
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Table structure for table `oauth_access_token` */
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
`token_id` varchar(255) DEFAULT NULL,
`token` longblob,
`authentication_id` varchar(255) DEFAULT NULL,
`user_name` varchar(255) DEFAULT NULL,
`client_id` varchar(255) DEFAULT NULL,
`authentication` longblob,
`refresh_token` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `oauth_access_token` */
/*Table structure for table `oauth_approvals` */
DROP TABLE IF EXISTS `oauth_approvals`;
CREATE TABLE `oauth_approvals` (
`userId` varchar(255) DEFAULT NULL,
`clientId` varchar(255) DEFAULT NULL,
`scope` varchar(255) DEFAULT NULL,
`status` varchar(10) DEFAULT NULL,
`expiresAt` datetime DEFAULT NULL,
`lastModifiedAt` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `oauth_approvals` */
/*Table structure for table `oauth_client_details` */
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(255) NOT NULL,
`resource_ids` varchar(255) DEFAULT NULL,
`client_secret` varchar(255) DEFAULT NULL,
`scope` varchar(255) DEFAULT NULL,
`authorized_grant_types` varchar(255) DEFAULT NULL,
`web_server_redirect_uri` varchar(255) DEFAULT NULL,
`authorities` varchar(255) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(255) DEFAULT NULL,
`autoapprove` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `oauth_client_details` */
/*Table structure for table `oauth_client_token` */
DROP TABLE IF EXISTS `oauth_client_token`;
CREATE TABLE `oauth_client_token` (
`token_id` varchar(255) DEFAULT NULL,
`token` longblob,
`authentication_id` varchar(255) DEFAULT NULL,
`user_name` varchar(255) DEFAULT NULL,
`client_id` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `oauth_client_token` */
/*Table structure for table `oauth_code` */
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
`code` varchar(255) DEFAULT NULL,
`authentication` varbinary(2550) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `oauth_code` */
/*Table structure for table `oauth_refresh_token` */
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
`token_id` varchar(255) DEFAULT NULL,
`token` longblob,
`authentication` longblob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `oauth_refresh_token` */
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
2.4 手动添加客户端信息
insert into `oauth_client_details`(`client_id`,`resource_ids`,`client_secret`,`scope`,`authorized_grant_types`,`web_server_redirect_uri`,`authorities`,`access_token_validity`,`refresh_token_validity`,`additional_information`,`autoapprove`) values('my_server','product_api','$2a$10$CYX9OMv0yO8wR8rE19N2fOaXDJondci5uR68k2eQJm50q8ESsDMlC','read,
write','client_credentials,implicit,authorization_code,refresh_token,password','http://www.baidu
.com',NULL,NULL,NULL,NULL,'false');
# 密码123
三 父工程创建
3.1 导入pom依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
四 资源模块创建
4.1 导入pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!--lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
4.2 配置文件
server:
port: 9002
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///security_authority
username: root
password: 199748
main:
allow-bean-definition-overriding: true # 这个表示允许我们覆盖OAuth2放在容器中的bean对象
mybatis:
type-aliases-package: com.yqj.domain
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.yqj: debug
4.3 启动类
package com.yqj;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Copyright(C),2019-2021,XXX公司
* FileName: OAuth2ProductApplication
* Author: yaoqijun
* Date: 2021/2/25 15:02
*/
@SpringBootApplication
@MapperScan("com.yqj.mapper")
public class OAuth2ProductApplication {
public static void main(String[] args) {
SpringApplication.run(OAuth2ProductApplication.class,args);
}
}
4.4 资源controller
package com.yqj.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Copyright(C),2019-2021,XXX公司
* FileName: ProductController
* Author: yaoqijun
* Date: 2021/2/25 15:03
*/
@RestController
@RequestMapping("/product")
public class ProductController {
@GetMapping("/findAll")
public String findAll(){
return "success findAll...";
}
}
4.5 用户和角色类
将访问的资源作为OAuth2的资源来管理
- SysUser
package com.yqj.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
/**
* Copyright(C),2019-2021,XXX公司
* FileName: SysUser
* Author: yaoqijun
* Date: 2021/2/24 10:14
*/
@Data
public class SysUser implements UserDetails {
private Integer id;
private String username;
private String password;
private List<SysRole> roles;
@JsonIgnore
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@JsonIgnore
@Override
public boolean isAccountNonExpired() {
return true;
}
@JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
}
@JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@JsonIgnore
@Override
public boolean isEnabled() {
return true;
}
}
- SysRole
package com.yqj.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
/**
* Copyright(C),2019-2021,XXX公司
* FileName: SysRole
* Author: yaoqijun
* Date: 2021/2/24 10:15
*/
@Data
public class SysRole implements GrantedAuthority {
private Integer id;
private String roleName;
private String roleDesc;
@JsonIgnore
@Override
public String getAuthority() {
return roleName;
}
}
4.6 资源管理配置类
package com.yqj.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
/**
* Copyright(C),2019-2021,XXX公司
* FileName: OauthSourceConfig
* Author: yaoqijun
* Date: 2021/2/25 15:09
*/
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true)
public class OauthSourceConfig extends ResourceServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
//TokenStore是OAuth2保存token的接口
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("product_api") //指定当前资源的id
.tokenStore(tokenStore()); //指定保存token的方式
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//指定不同请求方式访问资源所需要的权限,一般查询是read,其余是write。
.antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
.antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')")
.and()
.headers().addHeaderWriter((request, response) -> {
response.addHeader("Access-Control-Allow-Origin", "*");//允许跨域
if (request.getMethod().equals("OPTIONS")) {//如果是跨域的预检请求,则原封不动向下传达请求头信息
response.setHeader("Access-Control-Allow-Methods", request.getHeader("AccessControl-Request-Method"));
response.setHeader("Access-Control-Allow-Headers", request.getHeader("AccessControl-Request-Headers"));
}
});
}
}
五 授权模块创建
5.1 导入pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!--lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
5.2 配置文件
server:
port: 9001
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///security_authority
username: root
password: 199748
main:
allow-bean-definition-overriding: true # 这个表示允许我们覆盖OAuth2放在容器中的bean对象
mybatis:
type-aliases-package: com.yqj.domain
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.yqj: debug
5.3 启动类
package com.yqj;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Copyright(C),2019-2021,XXX公司
* FileName: OAuthServerApplication
* Author: yaoqijun
* Date: 2021/2/25 15:15
*/
@SpringBootApplication
@MapperScan("com.yqj.mapper")
public class OAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(OAuthServerApplication.class,args);
}
}
5.4 所有认证的代码复制进来
image-20210226092720244.png5.5 SpringSecurity配置类
package com.yqj.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* Copyright(C),2019-2021,XXX公司
* FileName: WebSecurityConfig
* Author: yaoqijun
* Date: 2021/2/25 15:18
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login").permitAll()
.and()
.csrf().disable();
}
//AuthenticationManager对象在OAuth2认证服务中要使用,提前放入IOC容器中
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
5.6 OAuth2授权配置类
package com.yqj.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
/**
* Copyright(C),2019-2021,XXX公司
* FileName: OauthServerConfig
* Author: yaoqijun
* Date: 2021/2/25 15:22
*/
@Configuration
@EnableAuthorizationServer
public class OauthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
//从数据库中查询出客户端信息
@Bean
public JdbcClientDetailsService clientDetailsService(){
return new JdbcClientDetailsService(dataSource);
}
//token保存策略
@Bean
public TokenStore tokenStore(){
return new JdbcTokenStore(dataSource);
}
//授权信息保存策略
@Bean
public ApprovalStore approvalStore(){
return new JdbcApprovalStore(dataSource);
}
//授权码模式专用对象
@Bean
public AuthorizationCodeServices authorizationCodeServices(){
return new JdbcAuthorizationCodeServices(dataSource);
}
//指定客户端登录信息来源
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients();
security.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.approvalStore(approvalStore())
.authenticationManager(authenticationManager)
.authorizationCodeServices(authorizationCodeServices())
.tokenStore(tokenStore());
}
}
六 授权模式测试
- 访问地址 http://localhost:9001/oauth/authorize?response_type=code&client_id=my_server 跳转到SpringSecurity默认认证页面,提示用户登录个人账户
- 登录成功后询问用户是否给予操作资源的权限,具体给什么权限。Approve是授权,Deny是拒绝
- 跳转到回调地址并获取授权码
- 使用授权码到服务器申请通行令牌token
- 携带token访问资源
网友评论