基于SpringBoot+SpringSecurity实现简单的权限控制

前言
权限控制主要就是保证两方面的功能,1.验证:验证就是认证用户身份,一般采用用户名+密码的方式;2.鉴权:确认用户身份和权限,以便能够访问受保护的资源。

话不多说,直接上代码:
1.在pom文件中新增SpringSecurity依赖包,代码如下:

    
        org.springframework.boot
        spring-boot-starter-security
    

    
        org.springframework.boot
        spring-boot-actuator
    

2.新建数据库,包括用户表,资源表等,简单如下:
CREATE TABLE resource (
id bigint(20) NOT NULL AUTO_INCREMENT,
url varchar(255) DEFAULT NULL COMMENT ‘资源’,
roles varchar(255) DEFAULT NULL COMMENT ‘所需角色’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

CREATE TABLE user (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(32) DEFAULT NULL COMMENT ‘姓名’,
address varchar(64) DEFAULT NULL COMMENT ‘联系地址’,
username varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT ‘账号’,
password varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT ‘密码’,
roles varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT ‘角色’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

插入对应数据:
INSERT INTO resource VALUES (1, ‘/depart1/’, ‘ROLE_ADMIN,ROLE_MANAGER,ROLE_DEPART1’);
INSERT INTO resource VALUES (2, '/depart2/
’, ‘ROLE_ADMIN,ROLE_MANAGER,ROLE_DEPART2’);
INSERT INTO resource VALUES (3, ‘/user/’, ‘ROLE_ADMIN,ROLE_USER’);
INSERT INTO resource VALUES (4, '/admin/
’, ‘ROLE_ADMIN’);

INSERT INTO user VALUES (1, ‘Adam’, ‘beijing’, ‘adam’, ‘$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6’, ‘ROLE_USER’);
INSERT INTO user VALUES (2, ‘SuperMan’, ‘shanghang’, ‘super’, ‘$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6’, ‘ROLE_USER,ROLE_ADMIN’);
INSERT INTO user VALUES (3, ‘Manager’, ‘beijing’, ‘manager’, ‘$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6’, ‘ROLE_USER,ROLE_MANAGER’);
INSERT INTO user VALUES (4, ‘User1’, ‘shanghang’, ‘user1’, ‘$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6’, ‘ROLE_USER,ROLE_DEPART1’);
INSERT INTO user VALUES (5, ‘User2’, ‘shanghang’, ‘user2’, ‘$2a$10$9SIFu8l8asZUKxtwqrJM5ujhWarz/PMnTX44wXNsBHfpJMakWw3M6’, ‘ROLE_USER,ROLE_DEPART2’);

3.实现SpringSecurity的验证流程分析
认证
参与验证的要素(用户名,密码)在前端由表单提交,由网络传入后端后,会形成一个Authentication类的实例,该接口定义如下所示:

其中,getCredentials()返回一个Object Credentials,它代表凭据,也即密码,getPrincipal()返回一个Object Principal,它代表身份信息,就是用户名,getAuthorities()返回一组已经分发的权限。

有了Authentication的验证实例,验证流程主要这个实例来完成,它会依次穿个整个验证链,并存储在
SecurityContextHolder中。也可以伪造一个Authentication,骗过验证流程,获取所有权限,俗称后门。(UsernamePasswordAuthenticationToken继承AbstractAuthenticationToken,AbstractAuthenticationToken实现Authentication接口)
(用于通过数据库验证的DaoAuthenticationProvider继承AbstractUserDetailsAuthenticationProvider,AbstractUserDetailsAuthenticationProvider实现AuthenticationProvider接口)

验证流程分析:
Authentication解决了验证信息的问题,AuthenticationManager则解决了验证管理的问题,它是验证管理类的总接口,而具体的验证管理需要ProviderManager类,该类持有一个List providers属性,实际上是AuthenticationProvider实例构成的验证链,这些实例构成具体的验证流程,关系如下:

验证成功后,Authentication会被存入SecurityContextHolder,在验证未过期的有效时间内,验证会一直存在,而且可以在需要的时候 取出并操作。

具体的验证流程如下:
后端从前端的表单得到用户密码,包装成一个Authentication类的对象;
将Authentication对象传给“验证管理器”ProviderManager进行验证;
ProviderManager在一条链上依次调用AuthenticationProvider进行验证;
验证成功则返回一个封装了权限信息的Authentication对象(即对象的Collection属性被赋值);
将此对象放入安全上下文SecurityContext中;
需要时,可以将Authentication对象从SecurityContextHolder上下文中取出。

鉴权
鉴权是一系列判断用户是否具有访问资源的过程,如果登录的用户具有其中某个资源,则可以顺利访问,否则会抛出AccessDeniedException异常,进入异常处理程序。
流程如下:
1.用户访问/***资源时,系统接口FilterInvocationSecurityMetadataSource的实现类(自己定义)会调用getAttributes(Object object)方法来进行资源匹配,它会读取数据库中的配置表,对/**资源进行匹配,若匹配成功,则将访问/**资源的角色组成一个Collection返回,若匹配不成功,则说明/**不需要额外的访问权限;

2.鉴权的决策类判断当前用户当前是否能访问/**资源。系统接口AccessDecisionManager的实现类(自己实现)通过decide()方法判断用户是否具有访问权限,decide()方法中的参数可以获得当前用户的验证信息,第一步中获得资源所需角色信息,对这些角色信息进行匹配即可确定是否通过;

3.若鉴权成功,则用户顺利访问,否则在decide()方法中抛出AccessDeniedException异常,这个异常会被系统AccessDeniedHandler接口的实现类(自己实现)处理,它仅仅是生成一个json对象,转换为字符串返回给客户端。

4.源码
参考我的github项目地址:
https://github.com/TomasXiong/SpringSecurity

你可能感兴趣的:(基于SpringBoot+SpringSecurity实现简单的权限控制)