• Spring Security 基于URL的权限判断


    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登录成功以后正确返回 

    项目结构如下

     

  • 相关阅读:
    2018-2019-1 20165321 20165324 20165302 实验四 外设驱动程序设计
    2018-2019-1 20165324 20165302 20165321 《信息安全系统设计基础》 第三次实验
    2018-2019-1 20165321 《信息安全系统设计基础》第七周学习总结
    2018-2019-1 20165321 《信息安全系统设计基础》第六周学习总结
    20165321 20165302 02165324 实验二 固件程序设计
    2018-2019-1 20165321 《信息安全系统设计基础》第五周学习总结
    2018-2019-1 20165302 20165321 20165324 实验一 开发环境的熟悉
    2018-2019-1 201653121 《信息安全系统设计基础》第三周学习总结
    2017-2018-2 20179205 《网络攻防技术与实践》第四周学习
    2017-2018-2 20179205《网络攻防技术与实践》第三周学习
  • 原文地址:https://www.cnblogs.com/cjsblog/p/15651716.html
Copyright © 2020-2023  润新知