一 授权


授权的方式包括 web授权和方法授权,web授权是通过 url拦截进行授权,方法授权是通过 方法拦截进行授权。


1.他们都会调用 accessDecisionManager进 行授权决策,


2.若 web授权则拦 截器为FilterSecurityInterceptor;


3.若为方 法授权则拦截器为 MethodSecurityInterceptor。


3.如果同时通过 web 授权和方法授权则 先执行web授权,再执行方 法授权 ,最后决策通过,则允许访问资源,否则将禁止访问。




springboot License授权许可 spring boot 授权_spring


访问授权的方法:



springboot License授权许可 spring boot 授权_用户信息_02


 二 案例实战

2.1 初始化数据库

1.角色表

CREATE TABLE `t_role` ( `id` varchar(32) NOT NULL, `role_name` varchar(255) DEFAULT NULL, `description` varchar(255) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, `status` char(1) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `unique_role_name` (`role_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

insert into `t_role`(`id`,`role_name`,`description`,`create_time`,`update_time`,`status`) values ('1','管理员',NULL,NULL,NULL,'');

2.角色关联表

CREATE TABLE `t_user_role` ( `user_id` varchar(32) NOT NULL, `role_id` varchar(32) NOT NULL, `create_time` datetime DEFAULT NULL, `creator` varchar(255) DEFAULT NULL, PRIMARY KEY (`user_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

insert into `t_user_role`(`user_id`,`role_id`,`create_time`,`creator`) values ('1','1',NULL,NULL);

3.权限表

CREATE TABLE `t_permission` ( `id` varchar(32) NOT NULL, `code` varchar(32) NOT NULL COMMENT '权限标识符', `description` varchar(64) DEFAULT NULL COMMENT '描述', `url` varchar(128) DEFAULT NULL COMMENT '请求地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 

insert into `t_permission`(`id`,`code`,`description`,`url`) values ('1','p1','测试资源 1','/user/r1'),('2','p3','测试资源2','/user/r2');
 

4.角色权限表

CREATE TABLE `t_role_permission` ( `role_id` varchar(32) NOT NULL, `permission_id` varchar(32) NOT NULL, PRIMARY KEY (`role_id`,`permission_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 

insert into `t_role_permission`(`role_id`,`permission_id`) values ('1','1'),('1','2');

2.2 查询数据库权限

2.2.1 dao层

springboot License授权许可 spring boot 授权_用户信息_03

<!-- 查询用户信息 -->
    <select id="findPermissionsByUserId" resultType="com.ljf.spt.security.model.PermissionDto" >
		SELECT id,code,description,url FROM t_permission WHERE id IN (
		SELECT permission_id FROM t_role_permission WHERE role_id IN (
		SELECT role_id FROM t_user_role WHERE user_id = #{userId}
		)
		)
	</select>

2.2.2 service层

springboot License授权许可 spring boot 授权_spring boot_04

package com.ljf.spt.security.service;

import com.ljf.spt.security.dao.UserMapper;
import com.ljf.spt.security.model.PermissionDto;
import com.ljf.spt.security.model.UserDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: SpringDataUserDetailsService
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2021/08/14 09:44:20 
 * @Version: V1.0
 **/
@Service
public class SpringDataUserDetailsService implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //将来连接数据库根据账号查询用户信息
        UserDto userDto = userMapper.getUserByUsername(username);
        if(userDto == null){
            //如果用户查不到,返回null,由provider来抛出异常
            return null;


        }
        //权限
       // String [] authoritys={"p1"};
        //根据用户的id查询用户的权限
        List<PermissionDto> permissionsList =  userMapper.findPermissionsByUserId(userDto.getId());
        List<String> permissions = new ArrayList<>();
        permissionsList.forEach(c -> permissions.add(c.getCode()));
        //将permissions转成数组
        String[] permissionArray = new String[permissions.size()];
        permissions.toArray(permissionArray);
        UserDetails userDetails = User.withUsername(userDto.getUsername()).password(userDto.getPassword()).authorities(permissionArray).build();
        return userDetails;
    }
}

2.3 第一种方式web授权

2.3.1 在配置文件中设置


通过给 http.authorizeRequests() 添加多个子节点来定制需求到我们的URL, 进行灵活的授权控 制:



springboot License授权许可 spring boot 授权_用户信息_05



  1.http.authorizeRequests() 方法有多个子节点,每个 macher 按照他们的声明顺序执行。


( 2 )指定 "/user/r1"URL ,拥有 p1 权限能够访问


( 3 )指定 "/user/r2"URL ,拥有 p2 权限能够访问


4.指定了除了 r1 、 r2 、 之 外"/user/**"资源,同时通过身份认证就能够访问,这里使用SpEL(Spring Expression Language)表达式。。


( 6 )剩余的尚未匹配的资源,不做保护。


 这里需要注意:


规则的顺序是重要的,更具体的规则应该先写,也就是说 权限范围小的写在最上面,范围大的写在下面。



.antMatchers("/admin/**").hasRole("ADMIN")

.antMatchers("/admin/login").permitAll()


因为/ admin / login已经被/ admin / **规则匹配,因此第二个规则被忽略。

应该改为:

.antMatchers("/admin/login").permitAll()

.antMatchers("/admin/**").hasRole("ADMIN")


springboot License授权许可 spring boot 授权_List_06

 2.3.2 测试

1.登录:

springboot License授权许可 spring boot 授权_spring_07

 

springboot License授权许可 spring boot 授权_用户信息_08

 2.访问资源1

springboot License授权许可 spring boot 授权_spring_09

 3.访问资源2:可以看到无权限访问,

bejing用户的角色为管理员,只拥有权限为p1,p1的路径为:/user/r1

springboot License授权许可 spring boot 授权_List_10

springboot License授权许可 spring boot 授权_List_11

 2.4 第二种方式方法授权

从Spring Security2.0版 ,它支持服务层方法的安全性的支持。方法注权限校验有:                              @PreAuthorize,@PostAuthorize, @Secured三类注解。

2.4.1 配置@EnableGlobalMethodSecurity


我们可以在任何 @Configuration 实例上使用 @EnableGlobalMethodSecurity 注释来启用基于注解的安全性。




@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)



springboot License授权许可 spring boot 授权_spring_12


2.4.2 然后向方法(在类或接口上)添加注解就会限制对该方法的访问

这里在controller的方法设置权限 



springboot License授权许可 spring boot 授权_spring boot_13


2.4.3 测试

springboot License授权许可 spring boot 授权_spring boot_14

springboot License授权许可 spring boot 授权_List_15

访问资源1:

springboot License授权许可 spring boot 授权_用户信息_16

 访问资源2:

springboot License授权许可 spring boot 授权_spring_17

 2.5 方法注解的分析

使用如下代码可启用prePost注解的支持:

springboot License授权许可 spring boot 授权_spring_18

springboot License授权许可 spring boot 授权_spring boot_19