Nginx 靜態資源鑒權訪問


前言

相信許多的小伙伴使用過Nginx服務器,來代理網站頁面或者代理文件資源,配置簡單,靈活。但是若出現像帶權限的來訪問Nginx的靜態資源時,那簡單的配置將不生效。

原理

img

准備

需要用到的知識、工具有

  1. spingBoot

  2. nginx

  3. mysql

  4. 一些文件

開始

Nginx配置方式

我們來拿一個簡單的Server的配置舉例。

其中會出現幾個重要的信息

  1. /resource 下的 internal 屬性: 寫上這個屬性,即代表此前綴請求不對外開放,僅可以內部訪問
  2. /file 下的 proxy_pass 指提供文件鑒權服務的地址
	server {
        listen       90; # 監聽端口
        server_name  localhost; # 域名

				# 靜態資源前綴
        location /resource { # 靜態資源訪問前綴
            internal; # 內部訪問!!!! 此處非常重要
            alias C:/authFile/; # 代理的靜態文件目錄
        }

        # 鑒權前綴
        location /file {
            proxy_redirect off;
            proxy_set_header Host  $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:6001; # 指定提供文件鑒權服務的地址
        }

	}

Mysql 表配置

ER-圖

img

SQL腳本

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for auth_file
-- ----------------------------
DROP TABLE IF EXISTS `auth_file`;
CREATE TABLE `auth_file`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件地址',
  `role_id` int(255) NULL DEFAULT NULL COMMENT '角色ID',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `ROLE_ID`(`role_id`) USING BTREE,
  CONSTRAINT `ROLE_ID` FOREIGN KEY (`role_id`) REFERENCES `auth_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for auth_role
-- ----------------------------
DROP TABLE IF EXISTS `auth_role`;
CREATE TABLE `auth_role`  (
  `id` int(255) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名稱',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for auth_user
-- ----------------------------
DROP TABLE IF EXISTS `auth_user`;
CREATE TABLE `auth_user`  (
  `id` int(255) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶名稱',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for auth_user_role
-- ----------------------------
DROP TABLE IF EXISTS `auth_user_role`;
CREATE TABLE `auth_user_role`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `role_id` int(11) NULL DEFAULT NULL COMMENT '角色ID',
  `user_id` int(11) NULL DEFAULT NULL COMMENT '用戶ID',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `U`(`role_id`) USING BTREE,
  INDEX `R`(`user_id`) USING BTREE,
  CONSTRAINT `R` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `U` FOREIGN KEY (`role_id`) REFERENCES `auth_role` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

文件准備

文件結構圖

img

與之對應SQL表數據

四張表依次為 文件表、角色表、角色用戶表、用戶表

imgimgimgimg

SpringBoot配置

基本的DAO、實體不粘貼了,使用技術為Mybatis-plus

yml

server:
  port: 6001

# spring 配置
spring:
  application:
    name: auth-file
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: username
    password: password
    url: jdbc:mysql://mysql_address:port/auth-file?socketTimeout=30000&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true


# mybatis-plus 配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      update-strategy: ignored

鑒權Service

@Service
public class AuthService {

    @Resource
    UserRoleRepo userRoleRepo;
    @Resource
    FileRepo fileRepo;

    public Boolean auth(DownloadParams params) {
        QueryWrapper<UserRole> query = new QueryWrapper<>();
        query.eq("user_id", params.getUserId());
        List<Integer> currentUserRoles = userRoleRepo.selectList(query).stream()
                .map(UserRole::getRoleId)
                .collect(Collectors.toList());
        File file = fileRepo.selectById(params.getFileId());
        FileHolder.set(file.getFileName());
        if (currentUserRoles.contains(file.getRoleId())) {
            System.out.println("獲得授權,開始下載");
            return true;
        } else {
            System.out.println("該用戶沒有文件: " + file.getFileName() + " 的下載權限");
            return false;
        }
    }
}

下載Service

此處為重點,值得注意的是,下載的response的Header內X-Accel-Redirect 就是回調Nginx靜態前綴的關鍵所在

前面所提到的允許內部訪問,即此處處理

@Service
public class DownloadService {
    @Resource
    FileRepo fileRepo;

    public void download(HttpServletResponse response, String fileName) {
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        response.setHeader("Content-Type", "application/octet-stream; charset=utf-8");
        response.setHeader("X-Accel-Redirect", "/resource/" + fileName);
        response.setHeader("X-Accel-Charset", "utf-8");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "No-cache");
        response.setHeader("Expires", "0");
    }

}

Web接口

@RestController
@RequestMapping("/file")
public class NgxAuthFileHandler {

    @Resource
    AuthService authService;
    @Resource
    DownloadService downloadService;

    @GetMapping
    public String preview(DownloadParams params, HttpServletResponse response) {
        if (authService.auth(params)) {
            String fileName = FileHolder.get();
            downloadService.download(response, fileName);
            return "獲得授權,開始下載";
        } else {
            String fileName = FileHolder.get();
            return "該用戶沒有文件: " + fileName + " 的下載權限";
        }
    }


}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM