webpack简单配置,路由配置,接口拦截配置,基本文件配置

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack简单配置,路由配置,接口拦截配置,基本文件配置相关的知识,希望对你有一定的参考价值。

参考技术A 新建项目

  项目脚手架搭建  react

     相关文件

        webpack.config.js

           使用相关插件

              path

              html-webpack-plugin

                html文件处理插件

              clean-webpack-plugin

                清除上次打包文件插件

              copy-webpcak-plugin

                 打包时需要复制的相关文件的插件(比如一些报表文件模版)

              speed-measure-webpack-plugin

                 速度测量插件  (const  SpeedMeasurePlugin = require("speed-measure-webpack-plugin");  const smp = new SpeedMeasurePlugin();  const webpackConfig = smp.wrap()

              happypack

                一些loader进程管理

              打包配置

                

mode:’环境设置’,

  entry:‘入口文件设置’,

  output:{path:path.resovle(__dirname,’dist’),filename:’main_[hash].js’,publicPath:’根据环境设置url前缀(接口域名代理字符)’},

  models:{rules:[

说明:{

  test:‘正则匹配/.js/’

  exclude:‘排除。。。(可以设置后缀名或者文件路径)’

  include:‘包含。。。(可以设置后缀名或者文件路径)’

  loader:‘loader设置url-loader’或者use:[loader:‘  ’,oprios:{plugins:[插件设置]或者其他设置}](use[可以设置happy pack插件:happypack/loader ? id = ‘happypack插件配置的id’])



]},(loader配置)

    (loader配置顺序:如,url-loader,babel-loader,style-loader,css-loader,file-loader)

  resolve:{extensions:[’js’,’json’,’jsx’,’css’]},(在导入没有带后缀名的文件时,尝试在文件加入上面后缀名访问)

  plugins:[]    (插件配置)



        bable.config.js

           相关插件  (用法function(api) api.cache(true);

              presets:[

[‘@babel/preset-env’,

                 ‘targets’:{’browsers’:["last 2 versions”,"safari >= 7”,”ie >=9”,”chrome >=49”]}

],

                 '@babel/preset-react’

    ],

              return “plugins”:

      ["@babel/plugin-proposal-decorators", "legacy": true ],(类装饰器  旧:设置legacy时需要loose支持,有顺序)

               @babel/plugin-proposal-dynamic-import, ( import 处理插件)

               @bacel/plugin-transform-runtime,(将helper和polypill都改为从一个统一的地方引入,引入的对象和全局变量完全隔离)

["@babel/plugin-proposal-class-properties", "loose" : true ],(解析类的属性)

               @ babel / plugin-proposal-logic-assignment-operators, (如出现短路时的逻辑处理插件)

               [''@babel/plugin-proposal-optional-chaining'',loose:false],(可选链优化  深层嵌套优化处理插件)               

               [''@babel/plugin-proposal-pipeline-operator'',proposal:'minimal’],(解析管道运算符)

               ['@babel/plugin-proposal-nullish-coalescing-operator'',loose:false],(删除无效的合并运算符)

      @ babel / plugin-proposal-do-expressions,( 插件执行一个 do {多个条件语句}表达式,最终语句完成值是该 do 表达式的完成值 )

      @ babel / plugin-transform-spread ,(扩展运算符转换插件)

      ["@babel/plugin-proposal-object-rest-spread", "loose": true, "useBuiltIns": true ],(转扩展运算插件)

      ["@babel/plugin-transform-object-assign”],(插件支持Object.assign())

    [“import”,{libraryName: 'antd',libraryDirectory: 'es',style: true,}](and按需引入设置)

)

        package.json

           项目打包/启动相关插件

              webpack-dev-server

              webpack-cli

              webpack-merga

      cross-env  (插件解决window系统兼容问题)

        postcss.config.js

            可以做相关的浏览器版本兼容配置

            相关插件

               autoprefixer({prefer:false,plugin:loader=>[request(autoprefixer)(browsers:[‘ie’>=9,’Safari’>=6])]}})

      public文件

        一些公用文件存放

      dist文件(打包后的文件)

      src文件(项目主文件)

        assets文件(存放图片等资源)

        api相关文件(api接口处理文件)

        modules文件或者pages文件

      (store文件)

        utils文件

          request.js(axios拦截文件)

             (相关插件)axios、history(使用:引入createBrowserHistory(现代浏览器使用)、createMemoryHistory(手机端使用))createBrowserHistory({basename:‘基链接(环境域名)’,forceRefresh:true  /是否强制刷新整个页面})

                axios.defaults.withCredentials = true;  //设置cross跨域并设置访问权限允许跨域携带cookie信息

                拦截设置:

  axios.interceptors.request.use(function (config)  return config;(请求参数拦截处理,如:请求头添加token或者其他(config.[‘headers’].token=......)), function (error)  return Promise.reject(error););

                   axios.interceptors.response.use(function (response)  return response;(请求成功返回参数错误处理,如:返回不同状态码跳转不同页面,token失效重登录......), function (error)  return Promise.reject(error);(请求失败错误处理,如:登录失效,跳转重新登录));

          history.js(路由环境配置)

             配置原理(根据package.json文件里面配置的NODE_ENV==‘production’或者’development’加上webpack.config.js里面的Deserver.proxy设置的代理key来配置开发或者正式环境的url前缀,配合createBrowserHistory.basename设置)

          until.js    (公用方法文件)

        index.js(全局引入,如:utils.request、@babel/polyfill、assets/.peg、路由前缀在路由上全局配置)

        routers.js  (路由文件)

        app.js(正经的组建文件,设置页面大致框架和路由跳转设置,也能做一些全局设置)

        index.html(可以做全局引入三方资源)

————————————————————————————————————————

这里的webpack配置是根据webpack4.30版本配置,算不上目前最新版本,配置也比较繁琐,里面用了happypack快速启动快速打包的多线程插件可能会跟你项目的一些配置方式出现冲突。

Springboot 使用 SaToken 进行登录认证权限管理以及路由规则接口拦截

Springboot 使用 SaToken 进行登录认证、权限管理以及路由规则接口拦截


前言

Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。


还有踢人下线、账号封禁、路由拦截规则、微服务网关鉴权、密码加密等丰富功能
它不比 Shiro 和 SpringSecurity 的功能少,而且配置使用更加简单


一、引入和配置

先给你们看一下 Demo 文件结构

1.引入依赖

如果不需要将 token 信息存入 redis,只需要引入下面这一个依赖

<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.31.0</version>
</dependency>

如果需要将 token 存入 redis,则还需要引入下面的依赖(一般搭建单点登录服务器才需要使用 redis)

使用redis ,无需任何其他配置,只需要多引入下面几个依赖,然后下面的 yml 加一些配置,satoken 就可以自动存储到 redis,非常方便

<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式)-->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-dao-redis-jackson</artifactId>
    <version>1.31.0</version>
</dependency>
<!-- Sa-Token插件:权限缓存与业务缓存分离 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-alone-redis</artifactId>
    <version>1.31.0</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2、配置yml

如下代码,如果不需要使用 redis ,则删除 alone-redisspring redis配置,否则连接不到 redis 会报错

如果使用了 redis,我下面的配置是业务和鉴权分离的方式,也就是说,token 存储在 alone-redis 里面配置的数据库,我这里配置的是 0 号数据库,它和 spring reids 配置的数据库不冲突

server:
  port: 8081
# Sa-Token配置
sa-token:
  # token前缀
  # Token前缀 与 Token值 之间必须有一个空格。
  # 一旦配置了 Token前缀,则前端提交 Token 时,必须带有前缀,否则会导致框架无法读取 Token。
  # 由于Cookie中无法存储空格字符,也就意味配置 Token 前缀后,Cookie 鉴权方式将会失效,此时只能将 Token 提交到header里进行传输
  # token-prefix: Bearer
  # token 名称 (同时也是cookie名称)
  token-name: satoken
  # token 有效期,单位s 默认30天, -1代表永不过期
  timeout: 2592000
  # token 临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
  activity-timeout: -1
  # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
  is-concurrent: true
  # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
  is-share: false
  # token风格
  token-style: uuid
  # 是否输出操作日志
  is-log: true
  # 配置 Sa-Token 单独使用的 Redis 连接
  alone-redis:
    # Redis数据库索引(默认为0)
    database: 0
    # Redis服务器地址
    host: 127.0.0.1
    # Redis服务器连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)
    password:
    # 连接超时时间
    timeout: 10s
spring:
  # 配置业务使用的 Redis 连接
  redis:
    # Redis数据库索引(默认为0)
    database: 1
    # Redis服务器地址
    host: 127.0.0.1
    # Redis服务器连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)
    password:
    # 连接超时时间
    timeout: 10s


3、配置全局异常处理

这一步可以不配置,配置的作用是,在鉴权失败的时候,不会报错,而是返回给前端鉴权失败的原因,方便我们开发调试

下面的异常会在鉴权失败的时候自动返回到前端,无需我们手动抛出和返回

package pers.xuyijie.satokendemo.exception;

import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @author 徐一杰
 * @date 2022/9/23 16:45
 * @description SaToken全局异常拦截
 */
@RestControllerAdvice
public class GlobalExceptionHandler 

    /**
     * 全局异常拦截,鉴权失败不会报错,会返回给前端报错原因
      * @param e
     * @return
     */
    @ExceptionHandler
    public SaResult handlerException(Exception e) 
        e.printStackTrace();
        return SaResult.error(e.getMessage());
    




4、模拟用户角色和权限

这里我们给用户分配一下我们模拟的角色和权限,正常你们要从数据库读取用户的角色和拥有的权限

这里实现了 StpInterface 下面的方法,下面的方法会在接口鉴权之前自动调用,判断角色和权限,无需我们手动调用

package pers.xuyijie.satokendemo.permission;

import cn.dev33.satoken.stp.StpInterface;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 徐一杰
 * @date 2022/9/23 16:46
 * @description 获取当前账号的权限和角色列表,这个类下面的方法会在接口鉴权之前自动调用
 */
@Component
public class UserPermission implements StpInterface 

    /**
     * 返回一个账号所拥有的权限码集合
     * 即你在调用 StpUtil.login(id) 时写入的标识值。
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) 
        // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("user-add");
        list.add("user-delete");
        list.add("user-update");
        list.add("user-get");
        list.add("article-get");
        System.out.println("用户权限列表:" + list);
        return list;
    

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) 
        // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色
        List<String> list = new ArrayList<>();
        list.add("user");
        list.add("admin");
        list.add("super-admin");
        System.out.println("用户角色列表:" + list);
        return list;
    




5、配置拦截器

如果在高版本 SpringBoot (≥2.6.x) 下注册拦截器失效,则需要添加 @EnableWebMvc 注解才可以使用

下面我们配置的规则叫作路由拦截规则/user/** 意思就是接口地址为 /user 开头的所有接口,也就是说,下面的我们 UserController 里面的所有接口都在拦截范围内

package pers.xuyijie.satokendemo.config;

import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author 徐一杰
 * @date 2022/9/23 16:49
 * @description
 */
@SpringBootConfiguration
@EnableWebMvc
public class SaTokenConfigure implements WebMvcConfigurer 

    /**
     * 注册 Sa-Token 拦截器,打开注解式鉴权功能
     * 如果在高版本 SpringBoot (≥2.6.x) 下注册拦截器失效,则需要额外添加 @EnableWebMvc 注解才可以使用
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) 
        // 注册路由拦截器,自定义认证规则
        registry.addInterceptor(new SaInterceptor(handler -> 
            // 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
            SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
            // 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
            SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
            // 权限认证 -- 不同模块认证不同权限
            SaRouter.match("/user/**", r -> StpUtil.checkRole("user"));
            SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
            // 甚至你可以随意的写一个打印语句
            SaRouter.match("/**", r -> System.out.println("--------权限认证成功-------"));
        ).isAnnotation(true))
        //拦截所有接口
        .addPathPatterns("/**")
        //不拦截/user/doLogin登录接口
        .excludePathPatterns("/user/doLogin");
    




6、controller里调用satoken的方法

方法上面的注解是使用权限认证和拦截器的时候用的,下面我会讲到

我在下面的UserController演示了登录注销检查是否登录查看用户token获取token有效期对称加密非对称加密方法,具体的方法每一行代码的作用,都在注视中写出来了,等一下我们测试每一个方法,为大家展示运行结果并解析代码

package pers.xuyijie.satokendemo.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.basic.SaBasicUtil;
import cn.dev33.satoken.secure.SaBase64Util;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

/**
 * @author 徐一杰
 * @date 2022/9/23 15:52
 * @description
 */
@RestController
@RequestMapping("/user")
public class UserController 

    private static final String USERNAME = "xyj";
    private static final String PASSWORD = "123456";

    /**
     * 测试登录
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/doLogin")
    public SaResult  doLogin(String username, String password) 
        //这个方法会强制在浏览器弹出一个认证框
        SaBasicUtil.check("sa:123456");
        if(username.equals(USERNAME) && password.equals(PASSWORD)) 
            //这个是登录用户的主键,业务中你要从数据库中读取
            StpUtil.login(1);
            //获取登录生成的token
            tokenInfo = StpUtil.getTokenInfo();
            System.out.println(tokenInfo);
            return SaResult.ok("登录成功,会话ID为 " + StpUtil.getLoginId() + " ,Token为:" + StpUtil.getTokenValue());
        
        return SaResult.error("登录失败");
    

    /**
     * 查询登录状态
     * @return
     */
    @RequestMapping("/signOut")
    public SaResult signOut() 
        String loginId = null;
        if (StpUtil.isLogin())
            loginId = (String) StpUtil.getLoginId();
            StpUtil.logout();
        
        return SaResult.ok("会话ID为 " + loginId + " 的用户注销登录成功");
    

    /**
     * 查询登录状态
     * @return
     */
    @RequestMapping("/isLogin")
    public SaResult isLogin() 
        if (StpUtil.isLogin())
            return SaResult.ok("会话是否登录:" + StpUtil.isLogin() + " ,会话ID为 " + StpUtil.getLoginId());
        
        return SaResult.ok("会话是否登录:" + StpUtil.isLogin());
    

    /**
     * 根据Token值获取对应的账号id,如果未登录,则返回 null
     * @param tokenValue
     * @return
     */
    @RequestMapping("/getUserByToken/tokenValue")
    public SaResult getUserByToken(@PathVariable String tokenValue)
        return SaResult.ok((String) StpUtil.getLoginIdByToken(tokenValue));
    

    /**
     * 获取当前会话剩余有效期(单位:s,返回-1代表永久有效)
     * @return
     */
    @RequestMapping("/getTokenTimeout")
    public SaResult getTokenTimeout()
        return SaResult.ok(String.valueOf(StpUtil.getTokenTimeout()));
    

    @SaIgnore
    @RequestMapping("/encodePassword")
    public void encodePassword() throws Exception 
        /**
         * md5加盐加密: md5(md5(str) + md5(salt))
         */
        String md5 = SaSecureUtil.md5("123456");
        String md5BySalt = SaSecureUtil.md5BySalt("123456", "salt");
        System.out.println("MD5加密:" + md5);
        System.out.println("MD5加盐加密:" + md5BySalt);

        /**
         * AES对称加密
         */
        // 定义秘钥和明文
        String key = "123456";
        String text = "这是一个明文用于测试AES对称加密";
        // 加密
        String ciphertext = SaSecureUtil.aesEncrypt(key, text);
        System.out.println("AES加密后:" + ciphertext);
        // 解密
        String text2 = SaSecureUtil.aesDecrypt(key, ciphertext);
        System.out.println("AES解密后:" + text2);

        /**
         * RSA非对称加密
         */
        // 定义私钥和公钥
        HashMap<String, String> keyMap = SaSecureUtil.rsaGenerateKeyPair();
        String privateKey = keyMap.get("private");
        String publicKey = keyMap.get("public");
        // 文本
        String text1 = "这是一个明文用于测试RSA非对称加密";
        // 使用公钥加密
        String ciphertext1 = SaSecureUtil.rsaEncryptByPublic(publicKey, text1);
        System.out.println("公钥加密后:" + ciphertext1);
        // 使用私钥解密
        String text3 = SaSecureUtil.rsaDecryptByPrivate(privateKey, ciphertext1);
        System.out.println("私钥解密后:" + text3);

        /**
         * Base64
         */
        // 文本
        String text4 = "这是一个明文用于测试Base64";
        // 使用Base64编码
        String base64Text = SaBase64Util.encode以上是关于webpack简单配置,路由配置,接口拦截配置,基本文件配置的主要内容,如果未能解决你的问题,请参考以下文章

前端笔记整理(Vue)

Vue2+VueRouter2+webpack 构建项目实战:配置子路由

vue2.0学习笔记之webpack-simple模板中的路由简单配置案例

webpack简单配置

react路由懒加载,路由配置化,webpack自动导入saga文件--后台定义配置式路由

Vue2+VueRouter2+webpack 构建项目实战:配置路由,运行页面