springboot 整合 Spring Security 上篇

news2025/5/29 6:51:38

1.创建springBoot 项目工程(spring6.0的底层、JDK17)

1.添加依赖
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

配置完成启动访问controller会出现登录页面
在这里插入图片描述

默认用户user 密码 控制台uuid输出,跟踪源码可以看到
在这里插入图片描述

2 使用配置的用户名密码;
  security:
    user:
      name: admin
      password: 123456

使用自己配置的登录然后就可以访问控制层api

3.退出登录

http://127.0.0.1:8080/logout
在这里插入图片描述

2.基于内存的多用户管理

在这里插入图片描述

1.创建用户详情接口配置类


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

//自定义配置类实现用户详情
@Configuration
public class MyUserSecurityConfig {

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user1 = User.builder().username("admin").password("123456").build();
        UserDetails user2 = User.builder().username("test").password("123456").build();
        InMemoryUserDetailsManager memoryUserDetailsManager = new InMemoryUserDetailsManager();
        memoryUserDetailsManager.createUser(user1);
        memoryUserDetailsManager.createUser(user2);

        return memoryUserDetailsManager;
    }


}

访问接口登录 test test 报错:如下
在这里插入图片描述
必须加密
修改配置类

package com.example.db.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

//自定义类实现用户详情接口
@Configuration
public class MyUserSecurityConfig {

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user1 = User.builder().username("admin").password("123456")
                .roles("admin").build();
        UserDetails user2 = User.builder().username("test").password("123456")
                .roles("stu").build();
        InMemoryUserDetailsManager memoryUserDetailsManager = new InMemoryUserDetailsManager();
        memoryUserDetailsManager.createUser(user1);
        memoryUserDetailsManager.createUser(user2);

        return memoryUserDetailsManager;
    }

    //配置密码加密器
    //没有加密NoOpPasswordEncoder
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }


}

通过上面配置可以正常登录,访问api接口,配置文件中的用户失效

3.密码加密

1.CSDN密码泄露事件,数据库明文存储
1.前端密码加密给后端,使用相同的密码加密规则,前端加密对比数据库密码校验规则。

常见加密算法MD5 sha RSA

2、使用PasswordEncoder接口提供的实现类

加盐干扰因子
BCryptPasswordEncoder 加密和校验原始密码

BCryptPasswordEncoder cryptPasswordEncoder=new BCryptPasswordEncoder();
        String encode = cryptPasswordEncoder.encode("123456");

        String encode2 = cryptPasswordEncoder.encode("123456");
        String encode3 = cryptPasswordEncoder.encode("123456");
        log.info(encode);
        log.info(encode2);
        log.info(encode3);
        boolean pwd1 = cryptPasswordEncoder.matches("123456", encode);
        boolean pwd2 = cryptPasswordEncoder.matches("123456", encode2);
        boolean pwd3 = cryptPasswordEncoder.matches("123456", encode3);
        log.info("pwd1="+pwd1);
        log.info("pwd2="+pwd2);
        log.info("pwd3="+pwd3);

在这里插入图片描述
加密上面文明密码


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

//自定义类实现用户详情接口
@Configuration
public class MyUserSecurityConfig {

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user1 = User.builder().username("admin").password(passwordEncoder().encode("123456"))
                .roles("admin").build();
        UserDetails user2 = User.builder().username("test").password(passwordEncoder().encode("654321"))
                .roles("stu").build();
        InMemoryUserDetailsManager memoryUserDetailsManager = new InMemoryUserDetailsManager();
        memoryUserDetailsManager.createUser(user1);
        memoryUserDetailsManager.createUser(user2);

        return memoryUserDetailsManager;
    }

    //配置密码加密器
    //没有加密NoOpPasswordEncoder
    @Bean
    public PasswordEncoder passwordEncoder() {
//        return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();

    }


}

在这里插入代码片

返回登录信息测试
添加控制器

package com.example.db.control;

import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/loginUser")
    public Authentication loginUser(Authentication authentication) {
        return authentication;
    }

    @GetMapping("/loginUser2")
    public Principal loginUser2(Principal principal) {
        return principal;
    }

    @GetMapping("/loginUser3")
    public Principal loginUser3() {
        //通过安全上下文持有器
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication;
    }
}

访问接口返回登录用户的信息如下
在这里插入图片描述
配置权限

UserDetails user1 = User.builder().username("admin").password(passwordEncoder().encode("123456"))
                .roles("admin")
                .authorities("stu:del") //配置权限
{
	"authorities": [{
		"authority": "stu:del"
	}],
	"details": {
		"remoteAddress": "127.0.0.1",
		"sessionId": "026ED34E46FC9022C29B200090F14924"
	},
	"authenticated": true,
	"principal": {
		"password": null,
		"username": "admin",
		"authorities": [{
			"authority": "stu:del"
		}],
		"accountNonExpired": true,
		"accountNonLocked": true,
		"credentialsNonExpired": true,
		"enabled": true
	},
	"credentials": null,
	"name": "admin"
}
4.基于方法的授权

开启@EnableGlobalMethodSecurity(prePostEnabled = true)

package com.example.db.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
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.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;

import static org.springframework.security.config.Customizer.withDefaults;

//从 Spring Security 5.7.0-M2开始 WebSecurityConfigurerAdapter 被标记为过期,鼓励用户转向基于组件的 security 配置
@Configuration
@Slf4j
//全局方法授权

@EnableWebSecurity  // 启用SpringSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {


        http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry
                .anyRequest().authenticated());

        http.formLogin().permitAll();
        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/test/**");
    }


}


控制器配置

package com.example.db.control;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/student")
@RestController
public class StudentController {

    @GetMapping("/stu")
    @PreAuthorize("hasAuthority('stu')")
    public String test() {
        return "I am a student";
    }
}

5.处理结果返回JSON 前端好处理

响应报文VO

package com.example.db.pojo;

import lombok.Data;

/**
 * 自定义响应结构
 */
@Data
public class Result {

    // 响应业务状态
    private Integer code;

    // 响应消息
    private String message;

    // 响应中的数据
    private Object data;

    public Result() {
    }

    public Result(Object data) {
        this.code = 200;
        this.message = "OK";
        this.data = data;
    }

    public Result(String message, Object data) {
        this.code = 200;
        this.message = message;
        this.data = data;
    }

    public Result(Integer code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public static Result ok() {
        return new Result(null);
    }

    public static Result ok(String message) {
        return new Result(message, null);
    }

    public static Result ok(Object data) {
        return new Result(data);
    }

    public static Result ok(String message, Object data) {
        return new Result(message, data);
    }

    public static Result build(Integer code, String message) {
        return new Result(code, message, null);
    }

    public static Result build(Integer code, String message, Object data) {
        return new Result(code, message, data);
    }


}

1.认证成功处理
package com.example.db.config;

import com.example.db.pojo.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;

//认证成功处理器
@Component
@Slf4j
public class AuthorSuccesssHandler implements AuthenticationSuccessHandler {


    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Result result=Result.build(1,"登录成功");

        String responsejson=objectMapper.writeValueAsString(result);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(responsejson);
        response.getWriter().flush();



    }
}

在这里插入图片描述

2.认证失败处理器
package com.example.db.config;

import com.example.db.pojo.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
//认证失败处理器
@Component

public class AuthorFailHandler implements AuthenticationFailureHandler {

    @Autowired
   private ObjectMapper objectMapper;
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        Result result=Result.build(-1,"登陆失败");

        String responsejson=objectMapper.writeValueAsString(result);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(responsejson);
        response.getWriter().flush();
    }
}

在这里插入图片描述

3.退出登录处理器
package com.example.db.config;

import com.example.db.pojo.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;

//注销处理器
@Component
@Slf4j
public class AppLoginOutHandler implements LogoutSuccessHandler {
    @Autowired
    private ObjectMapper objectMapper;


    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Result result = Result.build(1, "退出登录成功");

        String responsejson = objectMapper.writeValueAsString(result);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(responsejson);
        response.getWriter().flush();
    }
}

在这里插入图片描述

4.资源访问拒绝处理器
package com.example.db.config;

import com.example.db.pojo.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;

//资源访问拒绝处理器
@Slf4j
@Component
public class AppAcessDeiedHandler implements AccessDeniedHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Result result = Result.build(0, "你没有权限访问资源");

        String responsejson = objectMapper.writeValueAsString(result);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(responsejson);
        response.getWriter().flush();
    }
}

在这里插入图片描述

5.配置各种处理器
package com.example.db.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;

//从 Spring Security 5.7.0-M2开始 WebSecurityConfigurerAdapter 被标记为过期,鼓励用户转向基于组件的 security 配置
@Configuration
@Slf4j
//全局方法授权

@EnableWebSecurity  // 启用SpringSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {

    //认证成功处理器
    @Autowired
    private AuthorSuccesssHandler authorSuccesssHandler;
    @Autowired
    //认证失败处理器
    private AuthorFailHandler authorFailHandler;

    //退出登录处理器

    @Autowired
    private AppLoginOutHandler appLoginOutHandler;

    //访问拒绝处理器
    @Autowired
    private AppAcessDeiedHandler appAcessDeiedHandler;


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {


        http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry
                .anyRequest().authenticated());

        http.formLogin()
                .successHandler(authorSuccesssHandler)//认证成功
                .failureHandler(authorFailHandler)//认证失败


                .permitAll();

        http.logout().logoutSuccessHandler(appLoginOutHandler); //退出登录
        http.exceptionHandling().accessDeniedHandler(appAcessDeiedHandler);//访问资源失败

        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/test/**");
    }


}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1278829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS 实现一键复制文本内容

1、演示&#xff1a; 2、代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>一键复制</title&g…

如何用Java实现扑克牌(附源码)

目录 一.扑克牌的数据结构 二.买牌(扑克牌的初始化) 三.洗牌 四.发牌 五.完整代码 Card.java CardList.java 六.测试 输出结果 一.扑克牌的数据结构 首先&#xff0c;扑克牌是一幅一幅的&#xff0c;除去大小王以外一共有52张&#xff0c;我们可以考虑用数组来存储…

常用装备生产ERP有哪几种?有哪些作用

装备生产业务涉及原材料采购、车间排产、班组生产评估、派工单、接单报价、委外发料、库存盘点、设备台账、图纸设计等诸多环节&#xff0c;而各环节数据的共享问题普遍存在于装备生产企业内部&#xff0c;同时也直接影响企业的生产效率和整体效益等。 企业外部环境的变化和行…

linux安装KingbaseES(人大金仓数据库)

KingbaseES V8 数据库简介 金仓数据库管理系统[简称:KingbaseES]是北京人大金仓信息技术股份有限公司[简称人大金仓]的核心产品&#xff0c;具有大型通用、"三高"&#xff08;高可靠、高性能、高安全&#xff09;、"三易"&#xff08;易管理、易使用、易扩…

记录华为云服务器(Linux 可视化 宝塔面板)-- 防火墙篇

文章目录 前言安装防火墙防火墙设置防火墙操作1.设置开机启动防火墙2.查看防火墙开放哪些端口3.重载防火墙配置&#xff08;修改配置后重新启动才生效&#xff09;4.查看防火墙状态5.开启防火墙6.关闭防火墙 若遇到无法开启查询已开放的端口查询端口是否开放&#xff08;80&…

springBoot整合task

springBoot整合task 文章目录 springBoot整合task开开关设置任务&#xff0c;并设置执行周期定时任务的相关配置 开开关 设置任务&#xff0c;并设置执行周期 Component public class MyBean {Scheduled(cron "0/1 * * * * ?")public void print(){System.out.prin…

TCP连接为什么是三次握手,而不是两次和四次

答案 阻止重复的历史连接同步初始序列号避免资源浪费 原因 阻止重复的历史连接&#xff08;首要原因&#xff09; 考虑这样一种情况&#xff1a; 客户端现在要给服务端建立连接&#xff0c;向服务端发送了一个SYN报文段&#xff08;第一次握手&#xff09;&#xff0c;以表示请…

Oracle(2-10) User-Managed Backups

文章目录 一、基础知识1、Terminology 术语2、User-Managed Backup/Recovery 用户管理的备份/恢复3、Get DB File Information 获取数据库文件信息4、Consistent Whole DB Backup 一致的整个数据库备份冷备份热备份 二、基础操作1、查找需要备份的各种文件2、整备操作冷备份热备…

【Element-ui】Link 文字链接 与 Radio 单选框

文章目录 前言一、Link 文字链接1.1 基础用法1.2 禁用状态1.3 下划线1.4 图标 二、Radio 单选框2.1 基础用法2.2 禁用状态2.3 单选框组2.4 按钮样式2.5 带有边框2.6 Radio Eventsinput事件 2.7 Radio-group Attributes 总结 前言 在前端开发中&#xff0c;用户界面的元素设计和…

Certum SSL证书

为了确保在线交易的安全性&#xff0c;以及保护敏感信息免受网络威胁&#xff0c;使用SSL&#xff08;Secure Socket Layer&#xff09;证书成为了必要选择。其中&#xff0c;波兰认证机构Certum提供的SSL证书以其高度的安全性和可信赖性&#xff0c;得到了全球用户的广泛认可。…

基于运算放大器的电压采集电路

一、运算放大器 运放推导的两个重要概念&#xff1a;虚短、虚断。 1、差分放大器 以差分放大器为例进行推导分析。 虚断–运放的"-“端、”“端的引脚电流接近为0&#xff1b; 根据基尔霍夫电流定律可知&#xff1a;iR1iRF&#xff0c;iR2iR3&#xff1b; iR1(Ui1-(V-…

二分查找边界问题——排序数组找元素第一次出现和最后一次出现

二分查找的边界逼近问题&#xff1a; 下面的代码&#xff0c;第一个函数会向左边界逼近&#xff0c;第二个函数会像右边界逼近&#xff01; 考虑left5,right6这种情况&#xff0c;如果5&#xff0c;6的值都是满足的条件的怎么办&#xff1f; 如果mid(leftright1)/2&#xff0c;…

Qt将打印信息输出到文件

将打印信息&#xff08;qDebug、qInfo、qWarning、qCritial等&#xff09;输出到指定文件来以实现简单的日志功能。 #include "mainwindow.h" #include <QApplication> #include <QLoggingCategory> #include <QMutex> #include <QDateTime>…

面试数据库八股文十问十答第二期

面试数据库八股文十问十答第二期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1.MySQL的主从复制 MySQL的主从复制是什么&#xff1f;MySQL主从复制是一种常见的…

Hdoop学习笔记(HDP)-Part.09 安装OpenLDAP

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

Java语法之字符串类型

String类 在Java中&#xff0c;使用String类定义字符串类型&#xff0c;如下&#xff1a; String s1"hello";System.out.println(s1); 字符串拼接 只要s1s2即可 在字符串中&#xff0c;如果俩个字符串进行相加&#xff0c;那他就是字符串拼接的意思 补充 如上&am…

Leetcode—704.二分查找【简单】

2023每日刷题&#xff08;四十七&#xff09; Leetcode—704.二分查找 实现代码 int lower_bound(int* arr, int numsSize, int tar) {int left 0, right numsSize;int mid left (right - left) / 2;while(left < right) {mid left (right - left) / 2;if(arr[mid] …

网页开发 JS基础

目录 JS概述 基本语法 数据类型内置方法 DOM对象 查找标签 绑定事件 操作标签 jQuery 查找标签 绑定事件 操作标签 Ajax请求 数据接口 前后端分离 ajax的使用 JS概述 一门弱类型的编程语言,属于基于对象和基于原型的脚本语言. 1 直接编写<script>console…

基于SpringBoot的旅游信息网【源码好优多】

简介 旅游信息网是一款介绍旅游相关内容的网站&#xff0c;分为前台和后台部分&#xff0c;其中前台用户注册以后可以浏览景点、景点详情、预订景点、酒店、车票、保险、以及浏览旅游攻略、个人信息修改、在线留言等&#xff0c;管理员在后台对景点、攻略、订单信息、酒店信息、…

【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(2)后端跨域、登录模块、springboot分层架构、IDEA修改快捷键、vue代码风格

项目笔记为项目总结笔记,若有错误欢迎指出哟~ 【项目专栏】 【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(1)spring boot项目搭建、vue项目搭建、微信小程序项目搭建 【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(2)后端跨域、登录模块、sp…