基 于 角 色 权 限 模 型 与 数 据 权 限 控 制

以 小 明 的 摄 影 作 品 管 理 系 统 为 例 , 从 零 基 础 搭 建 到 完 整 认 证 鉴 权 , 逐 步 演 示 Spring Security 的 接 入 流 程 。 涵 盖 基 础 接 入 、 角 色 权 限 扩 展 、 数 据 权 限 控 制 三 大 模 块 , 每 步 标 注 自 定 义 类 与 Spring Security 扩 展 点 , 配 代 码 、 注 释 和 逻 辑 说 明 。 使 用 MyBatisPlus 作 为 ORM 框 架 。

** 第 一 部 分 : 基 础 接 入 流 程 — 前 后 端 分 离 认 证 鉴 权 **

** 第 一 步 : 环 境 准 备 与 依 赖 引 入 **

** 目 的 **

搭 建 Spring Boot 基 础 项 目 , 引 入 Spring Security 及 前 后 端 分 离 必 需 组 件 , 使 用 MyBatisPlus 替 代 JPA 。

** 操 作 **

  1. ** 创 建 Spring Boot 项 目 **

    通 过 start.spring.io 创 建 , 选 择 Maven 、 Java 17+ , 添 加 依 赖 Spring Web 、 Spring Security 、 MyBatis Plus 、 MySQL Driver 、 Lombok 。

  2. ** Pom.xml 核 心 依 赖 **

<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> <!-- MyBatis Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency> <!-- MySQL驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency> <!-- JWT支持 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency> <!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

** 第 二 步 : 数 据 库 设 计 与 实 体 类 **

** 目 的 **

设 计 用 户 、 角 色 表 , 并 让 用 户 PO 类 实 现 Spring Security 的 UserDetails 接 口 。

** 操 作 **

  1. ** 数 据 库 表 设 计 **
CREATE TABLE sys_user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
password VARCHAR(100) NOT NULL COMMENT 'BCrypt加密密码',
email VARCHAR(100) COMMENT '邮箱',
enabled BOOLEAN DEFAULT TRUE COMMENT '账户是否启用'
); CREATE TABLE sys_role (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
role_name VARCHAR(50) NOT NULL UNIQUE COMMENT '角色名称(无ROLE_前缀)'
); CREATE TABLE sys_user_role (
user_id BIGINT,
role_id BIGINT,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES sys_user(id),
FOREIGN KEY (role_id) REFERENCES sys_role(id)
);
  1. ** 实 体 类 UserPo 实 现 UserDetails 接 口 **
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors; @Data
@TableName("sys_user")
public class UserPo implements UserDetails {
private Long id;
private String username;
private String password;
private String email;
private Boolean enabled = true;
private Set<RolePo> roles; @Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getRoleName()))
.collect(Collectors.toList());
} @Override
public boolean isAccountNonExpired() { return true; } @Override
public boolean isAccountNonLocked() { return true; } @Override
public boolean isCredentialsNonExpired() { return true; } @Override
public boolean isEnabled() { return enabled; }
}
  1. ** 角 色 实 体 类 RolePo **
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; @Data
@TableName("sys_role")
public class RolePo {
private Long id;
private String roleName;
}

** 第 三 步 : MyBatisPlus Mapper 层 **

** 目 的 **

使 用 MyBatisPlus Mapper 操 作 数 据 库 。

** 操 作 **

  1. ** UserMapper 接 口 **
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.Optional; public interface UserMapper extends BaseMapper<UserPo> {
Optional<UserPo> findByUsername(@Param("username") String username);
}
  1. ** RoleMapper 接 口 **
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param; public interface RoleMapper extends BaseMapper<RolePo> {
Optional<RolePo> findByRoleName(@Param("roleName") String roleName);
}

** 第 四 步 : Service 层 — 实 现 UserDetailsService **

** 目 的 **

实 现 Spring Security 的 UserDetailsService 接 口 , 配 置 密 码 编 码 器 。

** 操 作 **

  1. ** 自 定 义 UserDetailsService 实 现 类 **
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service; @Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService { private final UserMapper userMapper; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserPo user = userMapper.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在:" + username));
return user;
}
}
  1. ** 配 置 密 码 编 码 器 **
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; @Configuration
public class PasswordEncoderConfig { @Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

** 第 五 步 : Spring Security 配 置 类 **

** 目 的 **

配 置 认 证 规 则 、 授 权 规 则 、 JWT 过 滤 器 。

** 操 作 **

  1. ** 自 定 义 Security 配 置 类 **
import lombok.RequiredArgsConstructor;
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.configuration.AuthenticationConfiguration;
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.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class SecurityConfig { private final UserDetailsServiceImpl userDetailsService;
private final JwtAuthFilter jwtAuthFilter;
private final PasswordEncoder passwordEncoder; @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/login", "/api/auth/register").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/user/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder); return http.build();
} @Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}

** 第 六 步 : JWT 工 具 类 与 过 滤 器 **

** 目 的 **

实 现 JWT 生 成 、 验 证 、 提 取 用 户 名 , 并 通 过 过 滤 器 转 换 为 认 证 信 息 。

** 操 作 **

  1. ** JWT 工 具 类 JwtUtils **
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.function.Function; @Component
public class JwtUtils { @Value("${app.jwt.secret}")
private String secret; @Value("${app.jwt.expiration}")
private long expiration; public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
} public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
} public boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
} private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
return claimsResolver.apply(claims);
} private boolean isTokenExpired(String token) {
return extractClaim(token, Claims::getExpiration).before(new Date());
}
}
  1. ** JWT 认 证 过 滤 器 JwtAuthFilter **
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; @Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter { private final JwtUtils jwtUtils;
private final UserDetailsServiceImpl userDetailsService; @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateToken(jwt)) {
String username = jwtUtils.extractUsername(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("无法设置用户认证: {}", e);
} filterChain.doFilter(request, response);
} private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if (headerAuth != null && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7);
}
return null;
}
}

** 第 七 步 : 登 录 接 口 与 资 源 接 口 **

** 目 的 **

编 写 登 录 接 口 认 证 并 生 成 Token , 编 写 受 保 护 资 源 接 口 。

** 操 作 **

  1. ** 登 录 控 制 器 AuthController **
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*; @RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController { private final AuthenticationManager authenticationManager;
private final JwtUtils jwtUtils; @PostMapping("/login")
public ResponseEntity<JwtResponse> login(@RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginRequest.getUsername(),
loginRequest.getPassword()
)
); SecurityContextHolder.getContext().setAuthentication(authentication);
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String jwt = jwtUtils.generateToken(userDetails); return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getUsername()));
}
}

** 第 二 部 分 : 权 限 表 扩 展 指 南 — 基 于 角 色 权 限 模 型 **

** 一 、 数 据 库 扩 展 **

** 目 的 **

新 增 权 限 表 实 现 细 粒 度 权 限 控 制 。

** 操 作 **

  1. ** 新 增 权 限 表 结 构 **
CREATE TABLE sys_permission (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
permission_symbol VARCHAR(100) NOT NULL UNIQUE COMMENT '权限符号(如 user:add)',
permission_name VARCHAR(100) NOT NULL COMMENT '权限名称'
); CREATE TABLE sys_role_permission (
role_id BIGINT,
permission_id BIGINT,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES sys_role(id),
FOREIGN KEY (permission_id) REFERENCES sys_permission(id)
);

** 二 、 实 体 类 扩 展 **

** 目 的 **

修 改 角 色 与 用 户 实 体 类 关 联 权 限 。

** 操 作 **

  1. ** 新 增 权 限 实 体 类 PermissionPo **
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Set; @Data
@TableName("sys_permission")
public class PermissionPo {
private Long id;
private String permissionSymbol;
private String permissionName;
private Set<RolePo> roles;
}
  1. ** 修 改 角 色 实 体 类 RolePo **
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Set; @Data
@TableName("sys_role")
public class RolePo {
private Long id;
private String roleName;
private Set<PermissionPo> permissions;
private Set<UserPo> users;
}
  1. ** 修 改 用 户 实 体 类 UserPo 权 限 加 载 **
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<>();
for (RolePo role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
for (PermissionPo permission : role.getPermissions()) {
authorities.add(new SimpleGrantedAuthority(permission.getPermissionSymbol()));
}
}
return authorities;
}

** 三 、 MyBatisPlus Mapper 扩 展 **

** 目 的 **

添 加 权 限 相 关 Mapper 接 口 。

** 操 作 **

  1. ** PermissionMapper **
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.Optional; public interface PermissionMapper extends BaseMapper<PermissionPo> {
Optional<PermissionPo> findByPermissionSymbol(@Param("symbol") String symbol);
}

** 四 、 Service 层 扩 展 **

** 目 的 **

实 现 权 限 管 理 服 务 。

** 操 作 **

  1. ** 权 限 管 理 服 务 PermissionService **
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.stream.Collectors; @Service
@RequiredArgsConstructor
public class PermissionService { private final PermissionMapper permissionMapper;
private final RoleMapper roleMapper; @Transactional
public void assignPermissionToRole(Long roleId, String permissionSymbol) {
RolePo role = roleMapper.selectById(roleId);
PermissionPo permission = permissionMapper.findByPermissionSymbol(permissionSymbol)
.orElseGet(() -> {
PermissionPo p = new PermissionPo();
p.setPermissionSymbol(permissionSymbol);
p.setPermissionName(parsePermissionName(permissionSymbol));
permissionMapper.insert(p);
return p;
}); role.getPermissions().add(permission);
roleMapper.updateById(role);
} private String parsePermissionName(String symbol) {
return Arrays.stream(symbol.split(":"))
.map(word -> word.substring(0, 1).toUpperCase() + word.substring(1))
.collect(Collectors.joining(" "));
}
}

** 五 、 控 制 器 层 扩 展 — 使 用 权 限 注 解 **

** 目 的 **

通 过 @PreAuthorize 注 解 控 制 方 法 权 限 。

** 操 作 **

  1. ** 用 户 控 制 器 使 用 权 限 注 解 **
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; @RestController
@RequestMapping("/api/users")
public class UserController { @PostMapping
@PreAuthorize("hasAuthority('user:add')")
public ResponseEntity<?> addUser() {
return ResponseEntity.ok("添加用户");
} @DeleteMapping("/{id}")
@PreAuthorize("hasAuthority('user:delete')")
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
return ResponseEntity.ok("删除用户");
}
}

** 第 三 部 分 : 数 据 权 限 控 制 — 订 单 查 询 只 查 看 自 己 创 建 的 订 单 **

** 一 、 数 据 库 扩 展 — 订 单 表 **

** 目 的 **

设 计 订 单 表 关 联 创 建 人 。

** 操 作 **

  1. ** 订 单 表 结 构 **
CREATE TABLE sys_order (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_no VARCHAR(50) NOT NULL COMMENT '订单编号',
amount DECIMAL(10,2) NOT NULL COMMENT '订单金额',
creator_id BIGINT NOT NULL COMMENT '创建人ID',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (creator_id) REFERENCES sys_user(id)
);
  1. ** 订 单 实 体 类 OrderPo **
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime; @Data
@TableName("sys_order")
public class OrderPo {
private Long id;
private String orderNo;
private BigDecimal amount;
private Long creatorId;
private LocalDateTime createdAt;
}

** 二 、 MyBatisPlus Mapper 与 Service **

** 目 的 **

实 现 订 单 数 据 访 问 与 权 限 过 滤 。

** 操 作 **

  1. ** OrderMapper **
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List; public interface OrderMapper extends BaseMapper<OrderPo> {
List<OrderPo> findByCreatorId(@Param("creatorId") Long creatorId);
}
  1. ** 订 单 服 务 实 现 **
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.List; @Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService { private final OrderMapper orderMapper;
private final UserMapper userMapper; @Override
public List<OrderPo> findMyOrders() {
UserPo currentUser = getCurrentUser();
return orderMapper.findByCreatorId(currentUser.getId());
} @Override
public OrderPo findOrderById(Long id) {
OrderPo order = orderMapper.selectById(id);
UserPo currentUser = getCurrentUser(); if (!order.getCreatorId().equals(currentUser.getId())) {
throw new AccessDeniedException("无权访问此订单");
}
return order;
} private UserPo getCurrentUser() {
String username = SecurityContextHolder.getContext().getAuthentication().getName();
return userMapper.findByUsername(username).orElseThrow();
}
}

** 三 、 控 制 器 层 实 现 **

** 目 的 **

编 写 订 单 相 关 接 口 , 集 成 数 据 权 限 控 制 。

** 操 作 **

  1. ** 订 单 控 制 器 **
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; @RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController { private final OrderService orderService; @GetMapping
@PreAuthorize("hasAuthority('order:view')")
public ResponseEntity<List<OrderPo>> getMyOrders() {
List<OrderPo> orders = orderService.findMyOrders();
return ResponseEntity.ok(orders);
} @GetMapping("/{id}")
@PreAuthorize("hasAuthority('order:view')")
public ResponseEntity<OrderPo> getOrderById(@PathVariable Long id) {
OrderPo order = orderService.findOrderById(id);
return ResponseEntity.ok(order);
}
}

** 总 结 **

通 过 以 上 三 部 分 整 合 , 我 们 实 现 了 Spring Security 前 后 端 分 离 接 入 、 角 色 权 限 扩 展 、 数 据 权 限 控 制 的 完 整 流 程 。 核 心 要 点 如 下 :

  1. ** 基 础 接 入 ** : 实 现 用 户 认 证 与 JWT 授 权 。
  2. ** 权 限 扩 展 ** : 通 过 权 限 表 与 角 色 关 联 , 实 现 细 粒 度 权 限 控 制 。
  3. ** 数 据 权 限 ** : 在 Service 层 手 动 过 滤 数 据 , 确 保 用 户 只 能 查 看 自 己 创 建 的 订 单 。

整 个 系 统 兼 顾 了 安 全 性 与 灵 活 性 , 适 用 于 中 小 型 项 目 的 权 限 管 理 需 求 。

Spring Security前后端分离接入流程保姆级教程的更多相关文章

  1. 七:Spring Security 前后端分离登录,非法请求直接返回 JSON

    Spring Security 前后端分离登录,非法请求直接返回 JSON 解决方案 在 Spring Security 中未获认证的请求默认会重定向到登录页,但是在前后端分离的登录中,这个默认行为则 ...

  2. spring boot + spring security +前后端分离【跨域】配置 + ajax的json传输数据

    1.前言 网上各个社区的博客参差不齐 ,给初学者很大的困扰 , 我琢磨了一天一夜,到各个社区找资料,然后不断测试,遇到各种坑,一言难尽啊,要么源码只有一部分,要么直接报错... 最后实在不行,直接去看 ...

  3. vue + spring boot + spring security 前后端分离 携带 Cookie 登录实现 只写了个登录

    最近想弄一下vue 所以就自己给自己找坑入   结果弄的满身是伤 哈哈哈 首先我说下 前后端分离  跨域请求  我在网上找了一些  可是都是针对于 spring boot 的 我自己还有 securi ...

  4. Spring Security 前后端分离登录,非法请求直接返回 JSON

    hello 各位小伙伴,国庆节终于过完啦,松哥也回来啦,今天开始咱们继续发干货! 关于 Spring Security,松哥之前发过多篇文章和大家聊聊这个安全框架的使用: 手把手带你入门 Spring ...

  5. 八个开源的 Spring Boot 前后端分离项目,一定要收藏!

    八个开源的 Spring Boot 前后端分离项目 最近前后端分离已经在慢慢走进各公司的技术栈,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,我们也非常建议大家学习一下前 ...

  6. Sping Security前后端分离两种方案

    前言 本篇文章是基于Spring Security实现前后端分离登录认证及权限控制的实战,主要包括以下四方面内容: Spring Seciruty简单介绍: 通过Spring Seciruty实现的基 ...

  7. 七个开源的 Spring Boot 前后端分离项目,一定要收藏!

    前后端分离已经在慢慢走进各公司的技术栈,根据松哥了解到的消息,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,松哥也非常建议大家学习一下前后端分离开发,以免在公司干了两三年 ...

  8. Vue+Spring Boot 前后端分离的商城项目开源啦!

    新蜂商城 Vue 移动端版本开源啦! 去年开源新蜂商城项目后,就一直在计划这个项目 Vue 版本的改造,2020 年开始开发并且自己私下一直在测试,之前也有文章介绍过测试过程和存在的问题,修改完成后, ...

  9. Spring Cloud 前后端分离后引起的跨域访问解决方案

    背景 Spring Cloud 微服务试点改造,目前在尝试前后端分离. 前台A应用(本机8080端口),通过网管(本机8769端口)调用后台应用B(本机8082端口).应用C发布的http服务.. A ...

  10. SpringBoot+Vue豆宝社区前后端分离项目手把手实战系列教程01---搭建前端工程

    豆宝社区项目实战教程简介 本项目实战教程配有免费视频教程,配套代码完全开源.手把手从零开始搭建一个目前应用最广泛的Springboot+Vue前后端分离多用户社区项目.本项目难度适中,为便于大家学习, ...

随机推荐

  1. L-非常可乐 BFS

    题目 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多.但 ...

  2. CF1710D Recover the Tree

    CF1710D Recover the Tree 题意 根据题意构造出一棵合法的树. 有 \(n\) 个点.\(a_{i,j}=\{0,1\},i \le j\) 表示编号在 \([i,j]\) 的点 ...

  3. 利用Python进行数据分析第二天

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  4. 解决远程桌面XRDP连接黑屏

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  5. java 静态代码块 静态方法

    (一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序 ...

  6. 以下是基于 **Ollama平台模型列表** 的分类与简介,按核心功能与特性划分:

    以下是基于 Ollama平台模型列表 的分类与简介,按核心功能与特性划分: 一.基础大语言模型(General LLMs) 模型名称 参数规模 特点简介 Llama3.3 70B 当前最强开源模型,性 ...

  7. XPOSED优秀模块列表 --- Xposed-LowRamDevice

      您的手机是低内存设备吗?你决定!点击 Module Settings 中的 isLowRamDevice 进行选择. 这个 Xposed 模块让你切换ActivityManager.isLowRa ...

  8. KAL1 LINUX 官方文档之虚拟机版本 --- 在 Kali(主机)上安装 VirtualBox (更新于2022)

    在 Kali(主机)上安装 VirtualBox 您可以在Kali Linux 上安装 VirtualBox ,允许您在 Kali Linux 中使用虚拟机 (VM).但是,如果您想将 Kali Li ...

  9. 基于MSWA相继加权平均的交通流量分配算法matlab仿真

    1.程序功能描述 基于MSWA相继加权平均的交通流量分配算法matlab仿真.如图所示交通网络中,包含6个节点.11各路段.9个OD对.经枚举可得每个OD对间存在3条无折返有效路径,共27条. 2.测 ...

  10. m基于BP译码算法的LDPC编译码matlab误码率仿真,对比不同的码率

    1.算法仿真效果 matlab2022a仿真结果如下: 2.算法涉及理论知识概要 低密度奇偶校验码(Low-Density Parity-Check Code, LDPC码)是一种高效的前向纠错码,广 ...