授权服务器的配置请参考我的上一篇博文:https://blog.csdn.net/qq_31404603/article/details/89853588
资源服务器的配置的时候,首先需要一个可以访问资源的接口,这个接口就是指对资源进行增删改查的操作,每个操作对应一种权限,这个权限也是归由SpringSecurity所管理的,实现了这些接口之后,就可以开始配置鉴权服务器的IP,简易版的配置如下,代码已上传GitHub:https://github.com/meiszl/SpringBoot_Security_Oauth20
资源服务器SQL:
/*
SQLyog v12.2.6 (64 bit)
MySQL - 8.0.15 : Database - oauth2_resource
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_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 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`oauth2_resource` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `oauth2_resource`;
/*Table structure for table `tb_content` */
DROP TABLE IF EXISTS `tb_content`;
CREATE TABLE `tb_content` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`category_id` bigint(20) NOT NULL COMMENT '内容类目ID',
`title` varchar(200) DEFAULT NULL COMMENT '内容标题',
`sub_title` varchar(100) DEFAULT NULL COMMENT '子标题',
`title_desc` varchar(500) DEFAULT NULL COMMENT '标题描述',
`url` varchar(500) DEFAULT NULL COMMENT '链接',
`pic` varchar(300) DEFAULT NULL COMMENT '图片绝对路径',
`pic2` varchar(300) DEFAULT NULL COMMENT '图片2',
`content` text COMMENT '内容',
`created` datetime DEFAULT NULL,
`updated` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `category_id` (`category_id`),
KEY `updated` (`updated`)
) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8;
/*Data for the table `tb_content` */
insert into `tb_content`(`id`,`category_id`,`title`,`sub_title`,`title_desc`,`url`,`pic`,`pic2`,`content`,`created`,`updated`) values
(28,89,'标题','子标题','标题说明','http://www.jd.com',NULL,NULL,NULL,'2019-04-07 00:56:09','2019-04-07 00:56:11'),
(29,89,'ad2','ad2','ad2','http://www.baidu.com',NULL,NULL,NULL,'2019-04-07 00:56:13','2019-04-07 00:56:15'),
(30,89,'ad3','ad3','ad3','http://www.sina.com.cn',NULL,NULL,NULL,'2019-04-07 00:56:17','2019-04-07 00:56:19'),
(31,89,'ad4','ad4','ad4','http://www.funtl.com',NULL,NULL,NULL,'2019-04-07 00:56:22','2019-04-07 00:56:25');
/*Table structure for table `tb_content_category` */
DROP TABLE IF EXISTS `tb_content_category`;
CREATE TABLE `tb_content_category` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '类目ID',
`parent_id` bigint(20) DEFAULT NULL COMMENT '父类目ID=0时,代表的是一级的类目',
`name` varchar(50) DEFAULT NULL COMMENT '分类名称',
`status` int(1) DEFAULT '1' COMMENT '状态。可选值:1(正常),2(删除)',
`sort_order` int(4) DEFAULT NULL COMMENT '排列序号,表示同级类目的展现次序,如数值相等则按名称次序排列。取值范围:大于零的整数',
`is_parent` tinyint(1) DEFAULT '1' COMMENT '该类目是否为父类目,1为true,0为false',
`created` datetime DEFAULT NULL COMMENT '创建时间',
`updated` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`,`status`) USING BTREE,
KEY `sort_order` (`sort_order`)
) ENGINE=InnoDB AUTO_INCREMENT=98 DEFAULT CHARSET=utf8 COMMENT='内容分类';
/*Data for the table `tb_content_category` */
insert into `tb_content_category`(`id`,`parent_id`,`name`,`status`,`sort_order`,`is_parent`,`created`,`updated`) values
(30,0,'LeeShop',1,1,1,'2015-04-03 16:51:38','2015-04-03 16:51:40'),
(86,30,'首页',1,1,1,'2015-06-07 15:36:07','2015-06-07 15:36:07'),
(87,30,'列表页面',1,1,1,'2015-06-07 15:36:16','2015-06-07 15:36:16'),
(88,30,'详细页面',1,1,1,'2015-06-07 15:36:27','2015-06-07 15:36:27'),
(89,86,'大广告',1,1,0,'2015-06-07 15:36:38','2015-06-07 15:36:38'),
(90,86,'小广告',1,1,0,'2015-06-07 15:36:45','2015-06-07 15:36:45'),
(91,86,'商城快报',1,1,0,'2015-06-07 15:36:55','2015-06-07 15:36:55'),
(92,87,'边栏广告',1,1,0,'2015-06-07 15:37:07','2015-06-07 15:37:07'),
(93,87,'页头广告',1,1,0,'2015-06-07 15:37:17','2015-06-07 15:37:17'),
(94,87,'页脚广告',1,1,0,'2015-06-07 15:37:31','2015-06-07 15:37:31'),
(95,88,'边栏广告',1,1,0,'2015-06-07 15:37:56','2015-06-07 15:37:56'),
(96,86,'中广告',1,1,1,'2015-07-25 18:58:52','2015-07-25 18:58:52'),
(97,96,'中广告1',1,1,0,'2015-07-25 18:59:43','2015-07-25 18:59:43');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
这里面的权限只是随机编的,资源服务器一般根据项目需求去搭建,此处仅仅是举一个示例。
POM依赖:
注意这个地方的Oauth2.0依赖一定要选择Spring-Cloud整合的依赖如果选择SpringSecurity的依赖在配置application的时候会找不到授权服务器,具体可能是底层依赖的问题:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringBoot_Security_Oauth2.0</artifactId>
<groupId>com.meiszl</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-security-oauth2-resource</artifactId>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<!-- 排除 tomcat-jdbc 以使用 HikariCP -->
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.meiszl.Oauth2resources.Oauth2ResourcesApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
POJO类:
package com.meiszl.Oauth2resources.pojo;
import lombok.Data;
import java.sql.Timestamp;
@Data
public class tb_content {
private Long id;
private Long category_id;
private String title;
private String sub_title;
private String title_desc;
private String url;
private String pic;
private String pic2;
private String content;
private Timestamp created;
private Timestamp updated;
}
Mapper类实现MyBatis-plus接口:
package com.meiszl.Oauth2resources.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.meiszl.Oauth2resources.pojo.tb_content;
public interface TbContentMapper extends BaseMapper<tb_content> {
}
dto响应类示例:
package com.meiszl.Oauth2resources.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 通用的返回对象
* <p>
* Description:
* </p>
*
* @author Lusifer
* @version v1.0.0
* @date 2019-04-07 00:09:49
* @see com.meiszl.Oauth2resources.dto
*/
@Data
public class ResponseResult<T> implements Serializable {
private static final long serialVersionUID = 8486468806063544444L;
/**
* 状态码
*/
private Integer state;
/**
* 消息
*/
private String message;
/**
* 返回对象
*/
private T data;
public ResponseResult() {
super();
}
public ResponseResult(Integer state) {
super();
this.state = state;
}
public ResponseResult(Integer state, String message) {
super();
this.state = state;
this.message = message;
}
public ResponseResult(Integer state, Throwable throwable) {
super();
this.state = state;
this.message = throwable.getMessage();
}
public ResponseResult(Integer state, T data) {
super();
this.state = state;
this.data = data;
}
public ResponseResult(Integer state, String message, T data) {
super();
this.state = state;
this.message = message;
this.data = data;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
result = prime * result + ((message == null) ? 0 : message.hashCode());
result = prime * result + ((state == null) ? 0 : state.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ResponseResult<?> other = (ResponseResult<?>) obj;
if (data == null) {
if (other.data != null) {
return false;
}
} else if (!data.equals(other.data)) {
return false;
}
if (message == null) {
if (other.message != null) {
return false;
}
} else if (!message.equals(other.message)) {
return false;
}
if (state == null) {
if (other.state != null) {
return false;
}
} else if (!state.equals(other.state)) {
return false;
}
return true;
}
@Override
public String toString() {
return "ResponseResult [state=" + state + ", message=" + message + ", data=" + data + "]";
}
}
Service类(此处仅仅实现数据的全部查询接口):
package com.meiszl.Oauth2resources.Service;
import com.meiszl.Oauth2resources.Mapper.TbContentMapper;
import com.meiszl.Oauth2resources.pojo.tb_content;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class TbContentService {
@Autowired
private TbContentMapper tbContentMapper;
public List<tb_content> findAll(){
return tbContentMapper.selectList(null);
}
}
Controller类:
package com.meiszl.Oauth2resources.Controller;
import com.meiszl.Oauth2resources.Mapper.TbContentMapper;
import com.meiszl.Oauth2resources.Service.TbContentService;
import com.meiszl.Oauth2resources.dto.ResponseResult;
import com.meiszl.Oauth2resources.pojo.tb_content;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class TbContentController {
@Autowired
private TbContentService tbContentService;
@GetMapping("/")
public ResponseResult<List<tb_content>> List(){
return new ResponseResult<List<tb_content>>(Integer.valueOf(HttpStatus.OK.value()), HttpStatus.OK.toString(), tbContentService.findAll());
}
}
ResourcesServerConfiguration类(资源服务器配置类):
package com.meiszl.Oauth2resources.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.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/").hasAuthority("SystemContent")
.antMatchers("/view/**").hasAuthority("SystemContentView")
.antMatchers("/insert/**").hasAuthority("SystemContentInsert")
.antMatchers("/update/**").hasAuthority("SystemContentUpdate")
.antMatchers("/delete/**").hasAuthority("SystemContentDelete");
}
}
application.yml配置(此处主要配置授权服务器地址用于鉴别token):
spring:
application:
name: oauth2-resource
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/oauth2_resources?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 123456
hikari:
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: MyHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
security:
oauth2:
client:
client-id: client
client-secret: secret
access-token-uri: http://localhost:8080/oauth/token
user-authorization-uri: http://localhost:8080/oauth/authorize
resource:
token-info-uri: http://localhost:8080/oauth/check_token
server:
port: 8081
servlet:
context-path: /contents
mybatis:
type-aliases-package: com.funtl.oauth2.resource.domain
mapper-locations: classpath:mapper/*.xml
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.security: INFO
org.springframework.security.oauth2: INFO