spring boot整合 spring security之授权访问

Posted 健康平安的活着

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring boot整合 spring security之授权访问相关的知识,希望对你有一定的参考价值。

一 授权

授权的方式包括 web授权和方法授权,web授权是通过 url拦截进行授权,方法授权是通过 方法拦截进行授权。
1.他们都会调用 accessDecisionManager进 行授权决策,
2.若 web授权则拦 截器为FilterSecurityInterceptor;
3.若为方 法授权则拦截器为 MethodSecurityInterceptor。
3.如果同时通过 web 授权和方法授权则 先执行web授权,再执行方 法授权 ,最后决策通过,则允许访问资源,否则将禁止访问。
访问授权的方法:

 二 案例实战

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层

 

	<!-- 查询用户信息 -->
    <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层

 

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, 进行灵活的授权控 制:
  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")

 

 2.3.2 测试

1.登录:

 

 2.访问资源1

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

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

 

 2.4 第二种方式方法授权

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

2.4.1 配置@EnableGlobalMethodSecurity

我们可以在任何 @Configuration 实例上使用 @EnableGlobalMethodSecurity 注释来启用基于注解的安全性。
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)

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

这里在controller的方法设置权限 

2.4.3 测试

 

访问资源1:

 访问资源2:

 2.5 方法注解的分析

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

 

 

以上是关于spring boot整合 spring security之授权访问的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot如何整合Redis

Spring Boot如何整合Redis

Spring Boot:Spring Boot整合FreeMarker

spring boot 系列之四:spring boot 整合JPA

Spring Boot系列Spring Boot整合持久层

Spring Boot 2.X - Spring Boot整合AMQP之RabbitMQ