1.  FilterSecurityInterceptor 源码阅读

org.springframework.security.web.access.intercept.FilterSecurityInterceptor

通过过滤器实现对HTTP资源进行安全处理。

该安全拦截器所需的 SecurityMetadataSource 类型为 FilterInvocationSecurityMetadataSource。

doFilter方法中直接调用invoke方法

基本都是调用父类的方法,那下面就重点看下父类 AbstractSecurityInterceptor 中相关方法

为安全对象实现安全拦截的抽象类。

AbstractSecurityInterceptor 将确保安全拦截器的正确启动配置。 它还将实现对安全对象调用的正确处理,即:

  1. 从 SecurityContextHolder 获取 Authentication 对象。
  2. 通过在SecurityMetadataSource中查找安全对象请求,确定请求是与安全调用还是公共调用相关(PS:简单地来讲,就是看一下请求的资源是不是受保护的,受保护的就是安全调用,就要权限,不受保护的就不需要权限就可以访问)。
  3. 对于受保护的调用(有一个用于安全对象调用的 ConfigAttributes 列表):
    1. 如果 Authentication.isAuthenticated() 返回 false,或者 alwaysReauthenticate 为 true,则根据配置的 AuthenticationManager 对请求进行身份验证。 通过身份验证后,将 SecurityContextHolder 上的 Authentication 对象替换为返回值。
    2. 根据配置的AccessDecisionManager授权请求。
    3. 通过配置的RunAsManager执行任何run-as替换。
    4. 将控制权传递回具体的子类,它实际上将继续执行对象。返回一个 InterceptorStatusToken 以便在子类完成对象的执行后,其 finally 子句可以确保 AbstractSecurityInterceptor 被调用并使用 finallyInvocation(InterceptorStatusToken) 正确处理。
    5. 具体的子类将通过 afterInvocation(InterceptorStatusToken, Object) 方法重新调用 AbstractSecurityInterceptor。
    6. 如果 RunAsManager 替换了 Authentication 对象,则将 SecurityContextHolder 返回到调用 AuthenticationManager 后存在的对象。
    7. 如果定义了AfterInvocationManager,则调用它并允许它替换将要返回给调用者的对象。
  4. 对于公开的调用(安全对象调用没有 ConfigAttributes):
    1. 如上所述,具体的子类将返回一个 InterceptorStatusToken,在执行完安全对象后,该 InterceptorStatusToken 随后被重新呈现给 AbstractSecurityInterceptor。 AbstractSecurityInterceptor 在它的 afterInvocation(InterceptorStatusToken, Object) 被调用时不会采取进一步的行动。
  5. 控制再次返回到具体的子类,以及应该返回给调用者的对象。然后子类会将该结果或异常返回给原始调用者。

下面具体来看

从这里我们可以知道返回null和空集合是一样的。

接下来看授权

这是我们要重点关注的,可以看到,授权靠的是 accessDecisionManager.decide(authenticated, object, attributes)

因此,我们想要实现自己的基于请求Url的授权只需自定义一个 AccessDecisionManager 即可

接下来,我们来具体实现一下

2.  自定义基于url的授权

先把Spring Security授权的大致流程流程摆在这儿:

自定义FilterInvocationSecurityMetadataSource

package com.example.security.core;

import com.example.security.service.SysPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher; import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map; /**
* @Author ChengJianSheng
* @Date 2021/12/2
*/
@Component
public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { @Autowired
private SysPermissionService sysPermissionService; private final AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
FilterInvocation fi = (FilterInvocation) object;
String url = fi.getRequestUrl();
String httpMethod = fi.getRequest().getMethod(); List<ConfigAttribute> attributes = new ArrayList<>(); Map<String, String> urlRoleMap = sysPermissionService.getAllUrlRole(); for (Map.Entry<String, String> entry : urlRoleMap.entrySet()) {
if (antPathMatcher.match(entry.getKey(), url)) {
return SecurityConfig.createList(entry.getValue());
}
} // 返回null和空列表是一样的,都表示当前访问的资源不需要权限,所有人都可以访问
return attributes;
// return null;
} @Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
} @Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}

这里需要说明一下,其实Spring Security里面说的role不一定表示的是我们自己建的那个角色表,我们可以这样理解,就是它这里的所谓role只是一个权限标识。我们在建表的时候,通常最基本的是5张表(用户表、角色表、权限表、用户角色关系表、角色权限关系表),我们可以把受保护的资源(通常是一个url)与角色关联起来,建立哪些角色可以访问哪些资源,也可以直接判断资源的权限(通常是权限编码/标识)。

只要有这个关系,剩下的就是写法不同而已。如果你把role理解成资源的权限标识的话,那么返回的Collection<ConfigAttribute>中就最多有一个元素,如果理解成角色的话,那么可能有多个元素。就这么点儿东西,写法不同而已,本质是一样的。

自定义AccessDecisionManager

package com.example.security.core;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component; import java.util.Collection; /**
* @Author ChengJianSheng
* @Date 2021/12/2
*/
@Component
public class MyAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
System.out.println(authorities);
System.out.println(configAttributes);
// 查看当前用户是否有对应的权限访问该保护资源
for (ConfigAttribute attribute : configAttributes) {
for (GrantedAuthority authority : authorities) {
if (authority.getAuthority().equals(attribute.getAttribute())) {
return;
}
}
}
throw new AccessDeniedException("Access is denied");
} @Override
public boolean supports(ConfigAttribute attribute) {
return true;
} @Override
public boolean supports(Class<?> clazz) {
return true;
}
}

decide方法的三个参数,依次表示:

  • 调用者(非空)
  • 被调用的安全对象
  • 与被调用的安全对象关联的配置属性

配置WebSecurityConfig

package com.example.security.config;

import com.example.security.core.MyAccessDecisionManager;
import com.example.security.core.MyFilterSecurityMetadataSource;
import com.example.security.core.MyUserDetailsService;
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.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private MyAccessDecisionManager myAccessDecisionManager;
@Autowired
private MyFilterSecurityMetadataSource myFilterSecurityMetadataSource; @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
} @Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.and()
.authorizeRequests()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O object) {
object.setSecurityMetadataSource(myFilterSecurityMetadataSource);
object.setAccessDecisionManager(myAccessDecisionManager);
return object;
}
})
.anyRequest().authenticated();
} @Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
} }

其它不重要的就直接贴出来了

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>security-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>security-demo</name> <properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build> </project>

application.yml

spring:
datasource:
url: jdbc:mysql://localhost:3306/demo126?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
jpa:
database: mysql
show-sql: true

SysPermissionEntity.java

package com.example.security.entity;

import lombok.Getter;
import lombok.Setter; import javax.persistence.*;
import java.io.Serializable; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
@Getter
@Setter
@Entity
@Table(name = "sys_permission")
public class SysPermissionEntity implements Serializable { @Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id; /** 权限编码(标识) */
private String code; /** 权限名称 */
private String name; /** 权限URL */
private String url; }

SysRoleEntity.java

package com.example.security.entity;

import lombok.Getter;
import lombok.Setter; import javax.persistence.*;
import java.io.Serializable;
import java.util.Set; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
@Getter
@Setter
@Entity
@Table(name = "sys_role")
public class SysRoleEntity implements Serializable { @Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id; /** 角色编码 */
private String code; /** 角色名称 */
private String name; @ManyToMany
@JoinTable(name = "sys_role_permission", joinColumns = {@JoinColumn(name = "role_id")}, inverseJoinColumns = {@JoinColumn(name = "permission_id")})
private Set<SysPermissionEntity> permissions;
}

SysUserEntity.java

package com.example.security.entity;

import lombok.Getter;
import lombok.Setter; import javax.persistence.*;
import java.io.Serializable;
import java.util.Set; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
@Getter
@Setter
@Entity
@Table(name = "sys_user")
public class SysUserEntity implements Serializable { @Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id; /** 用户名 */
private String username; /** 密码 */
private String password; @ManyToMany
@JoinTable(name = "sys_user_role",
joinColumns = {@JoinColumn(name = "user_id")},
inverseJoinColumns = {@JoinColumn(name = "role_id")})
private Set<SysRoleEntity> roles;
}

SysUserRepository.java

package com.example.security.repository;

import com.example.security.entity.SysUserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
public interface SysUserRepository extends JpaRepository<SysUserEntity, Integer>, JpaSpecificationExecutor<SysUserEntity> { SysUserEntity findByUsername(String username);
}

SysPermissionServiceImpl.java

package com.example.security.service.impl;

import com.example.security.entity.SysPermissionEntity;
import com.example.security.repository.SysPermissionRepository;
import com.example.security.service.SysPermissionService;
import org.springframework.stereotype.Service; import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
@Service
public class SysPermissionServiceImpl implements SysPermissionService { @Resource
private SysPermissionRepository sysPermissionRepository; @Override
public Map<String, String> getAllUrlRole() {
List<SysPermissionEntity> list = sysPermissionRepository.findAll();
return list.stream().collect(Collectors.toMap(SysPermissionEntity::getUrl, SysPermissionEntity::getCode));
}
}

MyUserDetails.java

package com.example.security.domain;

import lombok.AllArgsConstructor;
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.util.Collection;
import java.util.Set; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
@NoArgsConstructor
@AllArgsConstructor
public class MyUserDetails implements UserDetails { private String username;
private String password;
private boolean enabled;
private Set<SimpleGrantedAuthority> authorities; @Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
} @Override
public String getPassword() {
return password;
} @Override
public String getUsername() {
return username;
} @Override
public boolean isAccountNonExpired() {
return true;
} @Override
public boolean isAccountNonLocked() {
return true;
} @Override
public boolean isCredentialsNonExpired() {
return true;
} @Override
public boolean isEnabled() {
return enabled;
}
}

MyUserDetailsService.java

package com.example.security.core;

import com.example.security.domain.MyUserDetails;
import com.example.security.entity.SysPermissionEntity;
import com.example.security.entity.SysUserEntity;
import com.example.security.repository.SysUserRepository;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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 javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.Set;
import java.util.stream.Collectors; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
@Transactional
@Service
public class MyUserDetailsService implements UserDetailsService { @Resource
private SysUserRepository sysUserRepository; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUserEntity sysUserEntity = sysUserRepository.findByUsername(username);
if (null == sysUserEntity) {
throw new UsernameNotFoundException("用户不存在");
}
Set<SimpleGrantedAuthority> authorities = sysUserEntity.getRoles().stream()
.flatMap(roleId->roleId.getPermissions().stream())
.map(SysPermissionEntity::getCode)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toSet()); return new MyUserDetails(sysUserEntity.getUsername(), sysUserEntity.getPassword(), true, authorities);
}
}

HelloController.java

package com.example.security.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; /**
* @Author ChengJianSheng
* @Date 2021/12/6
*/
@RestController
@RequestMapping("/hello")
public class HelloController { @GetMapping("/sayHello")
public String sayHello() {
return "Hello";
} @GetMapping("/sayHi")
public String sayHi() {
return "Hi";
}
}

数据库脚本如下

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0; -- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限编码(标识)',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限名称',
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限URL',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES (1, 'home', '首页', '/home/**');
INSERT INTO `sys_permission` VALUES (2, 'user:add', '添加用户', '/user/add');
INSERT INTO `sys_permission` VALUES (3, 'user:delete', '删除用户', '/user/delete');
INSERT INTO `sys_permission` VALUES (4, 'hello:sayHello', '打招呼', '/hello/sayHello'); -- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色编码',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, 'employee', '员工');
INSERT INTO `sys_role` VALUES (2, 'engineer', '工程师');
INSERT INTO `sys_role` VALUES (3, 'leader', '组长'); -- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) NOT NULL COMMENT '角色ID',
`permission_id` int(11) NOT NULL COMMENT '权限ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES (1, 1, 1);
INSERT INTO `sys_role_permission` VALUES (2, 2, 1);
INSERT INTO `sys_role_permission` VALUES (3, 2, 2);
INSERT INTO `sys_role_permission` VALUES (4, 3, 1);
INSERT INTO `sys_role_permission` VALUES (5, 3, 2);
INSERT INTO `sys_role_permission` VALUES (6, 3, 3);
INSERT INTO `sys_role_permission` VALUES (7, 3, 4); -- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, 'zhangsan', '$2a$10$e4wFsFHQCNjPe5tTJMPkRuKGwmMGC45pfjMupY9nwbTuoKQ0bKc/u'); -- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户ID',
`role_id` int(11) NOT NULL COMMENT '角色ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1, 1);
INSERT INTO `sys_user_role` VALUES (2, 1, 2);
INSERT INTO `sys_user_role` VALUES (3, 1, 3); SET FOREIGN_KEY_CHECKS = 1;

浏览器访问 http://localhost:8080/hello/sayHi 正常返回,不用登录,因为没有在sys_permission表中配置该资源,也就是说它不是一个受保护的资源(公开资源)

访问http://localhost:8080/hello/sayHello则需要先登录,用zhangsan登录成功以后正确返回

项目结构如下

Spring Security 基于URL的权限判断的更多相关文章

  1. Spring Security 动态url权限控制(三)

    一.前言 本篇文章将讲述Spring Security 动态分配url权限,未登录权限控制,登录过后根据登录用户角色授予访问url权限 基本环境 spring-boot 2.1.8 mybatis-p ...

  2. spring security 3.1 实现权限控制

    spring security 3.1 实现权限控制 简单介绍:spring security 实现的权限控制,能够分别保护后台方法的管理,url连接訪问的控制,以及页面元素的权限控制等, secur ...

  3. 在ASP.NET MVC中实现基于URL的权限控制

    本示例演示了在ASP.NET MVC中进行基于URL的权限控制,由于是基于URL进行控制的,所以只能精确到页.这种权限控制的优点是可以在已有的项目上改动极少的代码来增加权限控制功能,和项目本身的耦合度 ...

  4. 基于Spring Security和 JWT的权限系统设计

    写在前面 关于 Spring Security Web系统的认证和权限模块也算是一个系统的基础设施了,几乎任何的互联网服务都会涉及到这方面的要求.在Java EE领域,成熟的安全框架解决方案一般有 A ...

  5. springboot整合security实现基于url的权限控制

    权限控制基本上是任何一个web项目都要有的,为此spring为我们提供security模块来实现权限控制,网上找了很多资料,但是提供的demo代码都不能完全满足我的需求,因此自己整理了一版. 在上代码 ...

  6. spring boot系列--spring security (基于数据库)登录和权限控制

    先说一下AuthConfig.java Spring Security的主要配置文件之一 AuthConfig 1 @Configuration 2 @EnableWebSecurity 3 publ ...

  7. Spring Security(15)——权限鉴定结构

    目录 1.1      权限 1.2      调用前的处理 1.2.1     AccessDecisionManager 1.2.2     基于投票的AccessDecisionManager实 ...

  8. Spring Security(14)——权限鉴定基础

    目录 1.1     Spring Security的AOP Advice思想 1.2     AbstractSecurityInterceptor 1.2.1    ConfigAttribute ...

  9. Spring Security基于Java配置

    Maven依赖 <dependencies> <!-- ... other dependency elements ... --> <dependency> < ...

随机推荐

  1. js计算精确度丢失问题解决

    (function () { var calc = { /* 函数,加法函数,用来得到精确的加法结果 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较为精 ...

  2. 在c中使用正则表达式

    今天学习编译原理的时候,用c写一个简易的文法识别器实验遇到了一个问题:要用正则表达式去识别正则文法里面的A->ω,A->Bω, 其中ω属于T的正闭包,也就是说我们对正则文法的产生式进行抽象 ...

  3. 链表中倒数第K个结点 牛客网 程序员面试金典 C++ Python

    链表中倒数第K个结点 牛客网 程序员面试金典 C++ Python 题目描述 输入一个链表,输出该链表中倒数第k个结点. C++ /* struct ListNode { int val; struc ...

  4. Luogu P2149 [SDOI2009]Elaxia的路线 | 图论

    题目链接 题解: 题面中给了最简洁清晰的题目描述:"求无向图中,两对点间最短路的最长公共路径". 对于这个问题我们可以先考虑图中的哪些边对这两对点的最短路产生了贡献. 比如说下面这 ...

  5. 重学STM32---(十)之CAN通信(二)

    目录 前言 程序编写 主代码 测试 前言   CAN协议是非常难的,但是在stm32中却是简单的,只需要我们配置寄存器即可,,,即使这样,我在学习的时候也遇到了许多困难 程序编写 1.开时钟,不用说 ...

  6. Java安全之Thymeleaf SSTI分析

    Java安全之Thymeleaf SSTI分析 写在前面 文章首发:https://www.anquanke.com/post/id/254519 最近看了一遍Thymeleaf,借此机会学习一下Th ...

  7. k8s入坑之路(12)ingress-nginx安装配置四层代理

    ingress官方文档地址:http://docs.kubernetes.org.cn/  https://feisky.gitbooks.io/kubernetes/content/plugins/ ...

  8. Pip安装Django超时(time out)解决方法

    (ll_env)learning_log$  pip install Django  执行该命令,始终报错,如上图 解决方法如下: pip install  -i http://pypi.douban ...

  9. idea断点调试

    基本使用 1 show execution point (Alt+F10):跳转到断点所执行的地方,也就是说你在看代码的时候,点到其他地方,一点这个按钮,就到了程序执行到当前哪行的代码的地方. 2 s ...

  10. 设置IDEA启动,不要自动打开上次使用时的项目

    打开idea时自动加载最近编辑的项目,很费时间,关闭设置如下