1 写在前面

关于spring security的介绍,网上一大堆,这里就不介绍了,这里直接使用springboot开始整合

2 整个流程

spring security授权和认证的流程大致和shiro差不多,其实跟我们自己基于RBAC的思想然后自定义拦截器进行权限拦截是一样的。

2.1 认证

认证的过程就是客户端用户登录,然后服务端将用户登录信息缓存起来,最后服务端将用户信息(基本信息、权限、token等)返回给客户端。

2.2 授权

授权的过程,首先客户端发起请求,携带token,服务端解析token,判断用户是否登录,再从缓存中查询用户的菜单,判断用户是否有权限请求菜单,最后返回数据给客户端

3 准备工作

此次继承基于RBAC思想实现,需要准备准备5张表(用户表、角色表、用户-角色中间表、菜单表、角色-菜单中间表)

DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu`  (`menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',`pid` bigint(20) NULL DEFAULT NULL COMMENT '上级菜单ID',`sub_count` int(5) NULL DEFAULT 0 COMMENT '子菜单数目',`type` int(11) NULL DEFAULT NULL COMMENT '菜单类型',`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单标题',`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组件名称',`component` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组件',`menu_sort` int(5) NULL DEFAULT NULL COMMENT '排序',`icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '图标',`path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '链接地址',`i_frame` bit(1) NULL DEFAULT NULL COMMENT '是否外链',`cache` bit(1) NULL DEFAULT b'0' COMMENT '缓存',`hidden` bit(1) NULL DEFAULT b'0' COMMENT '隐藏',`permission` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限',`create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建者',`update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新者',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`menu_id`) USING BTREE,UNIQUE INDEX `uniq_title`(`title`) USING BTREE,UNIQUE INDEX `uniq_name`(`name`) USING BTREE,INDEX `inx_pid`(`pid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 154 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统菜单' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (`role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '名称',`level` int(255) NULL DEFAULT NULL COMMENT '角色级别',`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',`data_scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据权限',`create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建者',`update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新者',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`role_id`) USING BTREE,UNIQUE INDEX `uniq_name`(`name`) USING BTREE,INDEX `role_name_index`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for sys_roles_menus
-- ----------------------------
DROP TABLE IF EXISTS `sys_roles_menus`;
CREATE TABLE `sys_roles_menus`  (`menu_id` bigint(20) NOT NULL COMMENT '菜单ID',`role_id` bigint(20) NOT NULL COMMENT '角色ID',PRIMARY KEY (`menu_id`, `role_id`) USING BTREE,INDEX `FKcngg2qadojhi3a651a5adkvbq`(`role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色菜单关联' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (`user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',`dept_id` bigint(20) NULL DEFAULT NULL COMMENT '部门名称',`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',`nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',`gender` varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',`phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号码',`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',`avatar_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像地址',`avatar_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像真实路径',`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',`is_admin` bit(1) NULL DEFAULT b'0' COMMENT '是否为admin账号',`enabled` bigint(20) NULL DEFAULT NULL COMMENT '状态:1启用、0禁用',`create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建者',`update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新者',`pwd_reset_time` datetime(0) NULL DEFAULT NULL COMMENT '修改密码的时间',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`user_id`) USING BTREE,UNIQUE INDEX `UK_kpubos9gc2cvtkb0thktkbkes`(`email`) USING BTREE,UNIQUE INDEX `username`(`username`) USING BTREE,UNIQUE INDEX `uniq_username`(`username`) USING BTREE,UNIQUE INDEX `uniq_email`(`email`) USING BTREE,INDEX `FK5rwmryny6jthaaxkogownknqp`(`dept_id`) USING BTREE,INDEX `FKpq2dhypk2qgt68nauh2by22jb`(`avatar_name`) USING BTREE,INDEX `inx_enabled`(`enabled`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 48 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统用户' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for sys_users_roles
-- ----------------------------
DROP TABLE IF EXISTS `sys_users_roles`;
CREATE TABLE `sys_users_roles`  (`user_id` bigint(20) NOT NULL COMMENT '用户ID',`role_id` bigint(20) NOT NULL COMMENT '角色ID',PRIMARY KEY (`user_id`, `role_id`) USING BTREE,INDEX `FKq4eq273l04bpu4efj0jd0jb98`(`role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户角色关联' ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

4 开始集成

4.1 依赖pom

    <dependencies><!--spring security--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- springboot redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--common-pool2--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>${commons-pool2.version}</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!--Mybatis plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><!--mybatis-plus-generator 搭配 freemarker使用--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>${mybatis-plus.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><!--mybatis-spring-starter--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis-spring-boot-starter.version}</version></dependency><!-- druid数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid-spring-boot-starter.version}</version></dependency><!--mysql连接工具--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--springboot web组件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--springboot test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><scope>provided</scope></dependency><!--common模块--><dependency><groupId>com.imysh</groupId><artifactId>zmy-common</artifactId><version>1.0.0</version></dependency></dependencies>

4.2 定义一个实现了UserDetails的自定义用户类User

package com.imysh.zmy.spring.security.config;import com.imysh.zmy.common.util.EmptyUtil;
import com.imysh.zmy.spring.security.dto.MenuDto;
import com.imysh.zmy.spring.security.dto.RoleDto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;/*** @author zhangmy* @date 2021/11/25 14:15* @description 1、定义spring security专用用户类*                  必须实现UserDetails,并重写那几个方法*                  这个类属性的获取是通过实现UserDetailsService接口的类中的loadUserByUsername()方法获取*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements UserDetails, Serializable {/*** 用户id*/private Long userId;/*** 用户名*/private String username;/*** 密码*/private String password;/*** token*/private String token;/*** 包含的角色*/private List<RoleDto> roles;/*** 拥有的菜单权限*/private List<MenuDto> menus;/*** 将用户的角色作为权限* @return*/@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<GrantedAuthority> auth = new ArrayList<>();if (EmptyUtil.isNotEmpty(roles)) {for (RoleDto role : roles) {auth.add(new SimpleGrantedAuthority(role.getRoleId().toString()));}}return auth;}@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}/*** 用户是否未过期* @return*/@Overridepublic boolean isAccountNonExpired() {return true;}/*** 用户是否未锁定* @return*/@Overridepublic boolean isAccountNonLocked() {return true;}/*** 用户凭证是否未过期* @return*/@Overridepublic boolean isCredentialsNonExpired() {return true;}/*** 用户是否启用* @return*/@Overridepublic boolean isEnabled() {return true;}
}

4.3 定义一个实现了UserDetailService的UserService

在这个类中重写loadUserByUsername方法,也就是咱们自定义获取用户的方法实现

package com.imysh.zmy.spring.security.config;import com.imysh.zmy.common.util.EmptyUtil;
import com.imysh.zmy.spring.security.mapper.SysMenuMapper;
import com.imysh.zmy.spring.security.mapper.SysRoleMapper;
import com.imysh.zmy.spring.security.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
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;import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @author zhangmy* @date 2021/11/25 14:33* @description 2、定义实现UserDetailsService接口的类,并重写loadUserByUsername方法,在此方法中根据用户名获取用户信息*                  返回的用户信息也是spring security专用的用户类,也就是com.imysh.zmy.spring.security.config.User*/
@Service
public class UserService implements UserDetailsService {@Autowiredprivate SysUserMapper userMapper;@Autowiredprivate SysRoleMapper roleMapper;@Autowiredprivate SysMenuMapper menuMapper;/*** 用户信息缓存*/static Map<String, User> userCache = new ConcurrentHashMap<>();@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user;// 判断缓存中是否包含当前用户if (userCache.containsKey(username)) {user = userCache.get(username);} else {// 用户基本信息user = this.userMapper.getSecurityUser(username);if (EmptyUtil.isNotEmpty(user)) {// 用户角色列表user.setRoles(roleMapper.getUserRoles(user.getUserId()));// 用户菜单列表user.setMenus(menuMapper.getUserMenus(user.getUserId()));// tokenString token = Base64.getEncoder().encodeToString((user.getUsername() + "_" + System.currentTimeMillis()).getBytes(StandardCharsets.UTF_8));user.setToken(token);// 将用户信息保存在缓存中userCache.put(username, user);}}return user;}
}

4.4 定义spring security的配置类

package com.imysh.zmy.spring.security.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;/*** @author zhangmy* @date 2021/11/25 15:20* @description 4、定义Spring Security配置类** 其中@EnableWebSecurity 表示是Spring Security的配置类* 其中@EnableGlobalMethodSecurity(prePostEnabled = true)表示开启@PreAuthorize、@PostAuthorize, @Secured这三个注解支持*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate CorsFilter corsFilter;@Autowiredprivate TokenFilter tokenFilter;@Beanpublic PasswordEncoder passwordEncoder() {//return new BCryptPasswordEncoder();return new PasswordEncoder() {/**** @param rawPassword 用户输入的密码* @return*/@Overridepublic String encode(CharSequence rawPassword) {return (String) rawPassword;}/**** @param rawPassword 用户输入的密码* @param encodedPassword 数据库存的加密后的密码* @return*/@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {return encodedPassword.contentEquals(rawPassword);}};}/*** 配置SpringSecurity相关信息** @param http* @throws Exception*/@Overridepublic void configure(HttpSecurity http) throws Exception {http.// 关闭csrfcsrf().disable()// 跨域处理过滤器.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class).addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)// 授权异常.exceptionHandling()// 防止iframe 造成跨域.and().headers().frameOptions().disable()// 不创建会话.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 静态资源等等.antMatchers(HttpMethod.GET,"/*.html","/**/*.html","/**/*.css","/**/*.js","/webSocket/**").permitAll()// swagger 文档.antMatchers("/swagger-ui.html").permitAll().antMatchers("/swagger-resources/**").permitAll().antMatchers("/webjars/**").permitAll().antMatchers("/*/api-docs").permitAll()// druid.antMatchers("/druid/**").permitAll()// 指定接口不进行验证.antMatchers("/auth/login", "/auth/logout").permitAll()// 所有请求都需要认证.anyRequest().authenticated();}
}

到这一步,已经可以实现用户登录的步骤了

4.5 定义TokenFilter类

package com.imysh.zmy.spring.security.config;import com.imysh.zmy.common.util.EmptyUtil;
import org.springframework.beans.factory.annotation.Autowired;
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.GenericFilterBean;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;/*** @author zhangmy* @date 2021/11/26 13:25* @description*/
@Component
public class TokenFilter extends GenericFilterBean {@Autowiredprivate UserService userService;@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;String token = this.resolveToken(httpServletRequest);if (EmptyUtil.isNotEmpty(token)) {// 解析token获取usernameString username = new String(Base64.getDecoder().decode(token.getBytes(StandardCharsets.UTF_8)));// 根据token获取鉴权信息UserDetails userDetails = this.userService.loadUserByUsername(username.split("_")[0]);UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));SecurityContextHolder.getContext().setAuthentication(authentication);}filterChain.doFilter(servletRequest, servletResponse);}/*** 获取Token** @param request /* @return /*/private String resolveToken(HttpServletRequest request) {return request.getHeader("Authorization");}
}

TokenFilter类用来在客户端发起请求时解析携带的token,得到当前登录的用户信息,然后下一步才能进行授权操作

4.6 权限校验

权限校验这里我们使用spring security自带的注解来实现

package com.imysh.zmy.spring.security.controller;import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author zhangmy* @date 2021/11/26 11:33* @description*/
@RestController
public class TestController {@GetMapping("/userList")@PreAuthorize("@permissionService.hasPermission('user:list')")public ResponseEntity uerList() {return ResponseEntity.ok("userList success");}@PreAuthorize("@permissionService.hasPermission('test:list')")@GetMapping("/testList")public ResponseEntity testList() {return ResponseEntity.ok("testList success");}
}

代码中的@PreAuthorize注解就是spring security用来做权限校验的,后面可以括号中的内容表示调用哪一个类的哪一个方法进行权限校验,这里就是调用permissionService类的hasPermission方法,参数就是权限标识,下面是PermissionService类

package com.imysh.zmy.spring.security.config;import com.imysh.zmy.common.util.EmptyUtil;
import com.imysh.zmy.spring.security.dto.MenuDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;/*** @author zhangmy* @date 2021/11/26 11:38* @description 验证授权*/
@Service("permissionService")
public class PermissionService {@Autowiredprivate UserService userService;public boolean hasPermission(String permission) {UserDetails userDetails = this.getCurrentUser();// 获取当前用户的所有权限//List<String> allPermissions = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());//return Arrays.stream(permissions).anyMatch(allPermissions::contains);List<String> allPermissions = this.getUserPermissions(userDetails);return allPermissions.contains(permission);}/*** 内部方法--获取用户权限* @param userDetails* @return*/private List<String> getUserPermissions(UserDetails userDetails) {if (userDetails instanceof User) {User user = (User) userDetails;List<MenuDto> menus = user.getMenus();if (EmptyUtil.isNotEmpty(menus)) {Set<String> menuSet = new HashSet<>();for (MenuDto menu : menus) {menuSet.add(menu.getPermission());}return new ArrayList<>(menuSet);}}return null;}/*** 获取当前登录用户** @return*/public UserDetails getCurrentUser() {final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication == null) {throw new RuntimeException("当前登录状态过期");}if (authentication.getPrincipal() instanceof UserDetails) {return (UserDetails) authentication.getPrincipal();}throw new RuntimeException("找不到当前登录的信息");}
}

到这里基本就整合完成了,当然这是简单版,没有使用JWT,密码也没有加密规则,还可以自定很多处理器完成如登录成功、失败的处理

5 效果验证

5.1 登录成功

5.2 登录失败

5.3 有权限访问

5.4 无权限访问

6 写在最后

总的来说Spring securit相对于shiro要更加复杂,更加重量级,但是它是spring家族成员,控制也更加细腻,可能学起来慢点,所以按照此教程,成功集成之后,再回头细看Spring Security的介绍也是可以的

SpringBoot 整合Spring Security(简单版)相关推荐

  1. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离

    在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与权限管理. ...

  2. springBoot整合spring security+JWT实现单点登录与权限管理前后端分离--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

  3. SpringBoot整合Spring Security【超详细教程】

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/Lee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 Spring Security是一个 ...

  4. 八、springboot整合Spring Security

    springboot整合Spring Security 简介 Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架.它是保护基于Spring的应用程序的事实标准. Spr ...

  5. SpringBoot 整合 Spring Security 实现安全认证【SpringBoot系列9】

    SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见. 程序员每天的CV 与 板砖,也要知其所以然,本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCl ...

  6. SpringBoot整合Spring Security——登录管理

    文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandle 1.2 CustomAuthenticationFailureHandler 1.3 ...

  7. SpringBoot整合Spring Security——第三章异常处理

    文章目录 一.常见异常 二.源码分析 三.处理异常 四.拓展spring security authenticationProvider用法及关闭不隐藏UserNotFoundException的解决 ...

  8. SpringBoot整合Spring Security

    个人资源与分享网站:http://xiaocaoshare.com/ SpringSecurity核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) 1.pom.xml < ...

  9. 31 | SpringBoot安全之整合Spring Security

    一.安全 应用程序的两个主要区域是"认证"和"授权"(或者访问控制),这两个主要区域是安全的两个目标. 身份验证意味着确认您自己的身份,而授权意味着授予对系统的 ...

最新文章

  1. 前台页面验证中需要注意的一个与VARCHAR2(N BYTE)和VARCHAR2(N CHAR)的小细节
  2. sql中的三元运算符
  3. sql优化的方法及思路_微生物发酵 技术优化思路 与方法
  4. 五一扣球练习2021-05-01
  5. php 5.3配置,php-5.3.3 说明及配置
  6. 无需复杂插件即可从Eclipse启动和调试Tomcat
  7. java方法不可覆盖_详解Java构造方法为什么不能覆盖,我的钻牛角尖病又犯了.......
  8. Excel-基本操作
  9. 单线程实现同时监听多个端口(windows平台c++代码)
  10. MyEclipse使用阿里p3c代码规范
  11. 如何在matlab坐标轴上输入希腊字符和开根号符号
  12. execl2010数据有效性验证,保存后丢失问题
  13. android手机固件升级原理,为什么常说Android手机千万别频繁的系统升级,背后的真实原因?...
  14. Android6.0通讯录权限问题
  15. LINUX 测试resnet18时,找不到模型 no checkpoint fount
  16. 运行cool edit时显示系统配置不正确
  17. Creating orkut style status update div-textbox using jQuery
  18. 正则表达式: 以英文字母开头,只能包含英文字母、数字、下划线
  19. 携程、艺龙、酷讯演绎在线旅游三国志
  20. 电信云堤·抗D(电信云堤清洗高防服务器)提供超强T级DDoS处理能力

热门文章

  1. 学术会议论文查重吗_学术论文会论文查重吗?
  2. qq浏览器如何关闭广告推荐
  3. Android搭建ftp服务器/客户端
  4. 抑郁症的复发风险到底有多高?如何预防抑郁症复发?
  5. CMake Error at /usr/lib/x86_64-linux-gnu/cmake/Qt5Core/Qt5CoreConfig.cmake:27 (message)
  6. arduino spi接线
  7. jeep智能手表软件测评中心的测试,功能强悍的Jeep智能表深度体验,用起来酷到没朋友...
  8. NVIDAI和ATI显卡比较,细研GPU工作流程
  9. powder design16.5记录
  10. 邓应海:黄金压力难突破,美盘还是空!最新黄金走势分析