SpringBoot2.3.4整合SpringSecurity实现权限管理
概述
Spring是⾮常流⾏的Java应⽤开发框架,Spring Security是基于Spring框架,提供了⼀套Web应⽤安全性的完整解决⽅案。主要有两个⽅⾯,⽤户认证(Authentication)和⽤户授权(Authorization),⽤户认证指的是验证某个⽤户是否为系统中的合法主体,也就是说⽤户能否访问该系统。⽤户授权指的是验证某个⽤户是否有权限执⾏某个操作。
SpringSecurity的主要特点如下:
和Spring⽆缝整合
全⾯的权限控制
专门为Web开发⽽设计
重量级框架
SpringSecurity更多知识请查阅
Shiro是另⼀个⾮常流⾏的权限控制框架,它是Apache旗下的产品,相对于Spring Security,Shiro有以下特点:轻量级,针对对性能有更⾼要求的互联⽹应⽤有更好的表现
通⽤性,不局限于Web环境,可以脱离Web环境使⽤,缺陷就是在Web环境下⼀些特定的需求需要⼿动编写代码定制
Shiro更多知识请查阅
对于如何选择权限框架,⼀般来说,常见的技术栈组合如下:
SSM + Shrio
Spring Boot/Spring Cloud + Spring Security
若想了解SpringBoot整合SpringSecurity+jwt的步骤,请参阅
若想了解SpringBoot整合Shiro的步骤,请参阅
相关概念
principal(主体):使⽤系统的⽤户或设备或从其他系统远程登录的⽤户
authentication(认证):权限管理系统确认⼀个主体的⾝份,允许主体进⼊系统,简单的说就"主体"证明⾃⼰是谁,也就是我们常说的登录操作
authorization(授权):将系统的"权⼒"授予给"主体",这样主体就拥有了操作系统的某些特定功能的能⼒
UserDetailsService:Spring Security提供的登录逻辑接⼝,当什么也没有配置的时候,账号和密码是由Spring Security⾃定义⽣成的,在实际开发中我们都是需要从数据库中查询出来,这样就需要实现该接⼝,⾃定义登录逻辑
UserDetails:上⾯登录接⼝返回的⽤户"主体",是系统默认的⽤户,常⽤的⽅法有以下⼏个:
//获取登录⽤户所有权限
Collection<?extends GrantedAuthority>getAuthorities();
//获取密码
String getPassword();
//获取⽤户名
String getUsername();
//判断账户是否过期
boolean isAccountNonExpired();
//判断账户是否被锁定
boolean isAccountNonLocked();
//判断密码是否过期
boolean isCredentialsNonExpired();
//判断当前⽤户是否可⽤
boolean isEnabled();
在使⽤的时候可以直接调⽤其实现类User就可以了,只需要传⼊⽤户名、密码和权限即可
public User(String username, String password, Collection<?extends GrantedAuthority> authorities){
this(username, password,true,true,true,true, authorities);
}
PasswordEncoder:密码加密,Spring Security提供的密码加密类,默认的密码解析器是BCryptPasswordEncoder,需要在配置⽂件中实例化,BCryptPasswordEncoder是对bcrypt强散列⽅法的具体实现,是基于Hash算法实现的单向加密,可以通过strength控制加密强度,默认10
新建表和初始化数据
需要使⽤的表有:
sys_user:⽤户表
shiro安全框架
sys_role:⾓⾊表
sys_menu:菜单权限表
sys_user_role:⽤户⾓⾊关联表
sys_role_menu:⾓⾊菜单关联表
persistent_logins:记住我登录表(Spring Security可以⾃动⽣成改表,⽤于记住我时保存⽤户信息)
建表语句和初始化数据如下:
CREATE TABLE`sys_user`(
`id`bigint(20)unsigned NOT NULL AUTO_INCREMENT COMMENT'主键ID',
`user_name`varchar(50)NOT NULL COMMENT'⽤户名',
`real_name`varchar(20)NOT NULL COMMENT'真实名称',
`password`varchar(64)NOT NULL COMMENT'密码',
`sex`tinyint(2)NOT NULL DEFAULT'10'COMMENT'性别10:男;11:⼥;12:其他',
`avatar`varchar(100)DEFAULT NULL COMMENT'头像路径',
`status`tinyint(2)NOT NULL DEFAULT'10'COMMENT'状态10:正常;11:锁定;12:注销',
`del_flag`tinyint(1)NOT NULL DEFAULT'0'COMMENT'删除标识0:未删除;1:已删除',
`create_by`varchar(20)DEFAULT NULL COMMENT'创建者',
`create_time`timestamp NULL DEFAULT NULL COMMENT'创建时间',
`update_by`varchar(20)DEFAULT NULL COMMENT'更新者',
`update_time`timestamp NULL DEFAULT NULL COMMENT'更新时间',
`remark`varchar(100)DEFAULT NULL COMMENT'备注',
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=3DEFAULT CHARSET=utf8 COMMENT='⽤户表';
INSERT INTO sys_user (user_name,real_name,password,sex,avatar,status,del_flag,create_by,create_time,update_by,update_time,remark)VALUES ('admin','超级管理员','$2a$10$j3XmUHGzMFLZFH.Qioq4Z.nM/iFMd4Wk6GDI.mC7U2yIztdyV6oUe',10,'',10,0,'admin','2020-09-30 08:34:18.0','admin','202 0-09-30 08:34:18.0','')
CREATE TABLE`sys_role`(
`id`bigint(20)unsigned NOT NULL AUTO_INCREMENT COMMENT'主键ID',
`role_code`varchar(20)NOT NULL COMMENT'⾓⾊编号',
`role_name`varchar(30)NOT NULL COMMENT'⾓⾊名称',
`status`tinyint(2)unsigned NOT NULL DEFAULT'10'COMMENT'⾓⾊状态10:正常;11:停⽤',
`del_flag`tinyint(1)NOT NULL DEFAULT'0'COMMENT'删除标识0:未删除;1:已删除',
`create_by`varchar(20)DEFAULT NULL COMMENT'创建者',
`create_time`timestamp NULL DEFAULT NULL COMMENT'创建时间',
`update_by`varchar(20)DEFAULT NULL COMMENT'更新者',
`update_time`timestamp NULL DEFAULT NULL COMMENT'更新时间',
`remark`varchar(100)DEFAULT NULL COMMENT'备注',
PRIMARY KEY(`id`)
)
ENGINE=InnoDB AUTO_INCREMENT=2DEFAULT CHARSET=utf8 COMMENT='⾓⾊表';
INSERT INTO sys_role (role_code,role_name,status,del_flag,create_by,create_time,update_by,update_time,remark)VALUES
('admin','超级管理员',10,0,'admin',NULL,'admin',NULL,NULL);
CREATE TABLE`sys_menu`(
`id`bigint(20)unsigned NOT NULL AUTO_INCREMENT COMMENT'主键ID',
`menu_name`varchar(50)NOT NULL COMMENT'菜单名称',
`parent_id`bigint(20)unsigned DEFAULT'0'COMMENT'⽗级菜单ID',
`order_num`tinyint(2)unsigned DEFAULT'0'COMMENT'显⽰顺序',
`url`varchar(100)NOT NULL DEFAULT'#'COMMENT'请求地址',
`menu_type`tinyint(2)unsigned DEFAULT NULL COMMENT'菜单类型10:⽬录;20:菜单;30:按钮',
`visible`tinyint(2)unsigned NOT NULL DEFAULT'10'COMMENT'菜单状态10:显⽰;20:隐藏',
`perms`varchar(100)DEFAULT NULL COMMENT'权限标识',
`icon`varchar(100)NOT NULL DEFAULT'#'COMMENT'菜单图标',
`create_by`varchar(20)DEFAULT NULL COMMENT'创建者',
`create_by`varchar(20)DEFAULT NULL COMMENT'创建者',
`create_time`timestamp NULL DEFAULT NULL COMMENT'创建时间',
`update_by`varchar(20)DEFAULT NULL COMMENT'更新者',
`update_time`timestamp NULL DEFAULT NULL COMMENT'更新时间',
`remark`varchar(100)DEFAULT NULL COMMENT'备注',
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=105DEFAULT CHARSET=utf8 COMMENT='菜单表';
INSERT INTO sys_menu (menu_name,parent_id,order_num,url,menu_type,visible,perms,icon,creat
e_by,create_time,update_by,update_time,remark)VA LUES
('系统管理',0,1,'#',10,10,'','#','admin',NULL,'admin',NULL,NULL)
,('⽤户管理',1,1,'/system/user',20,10,'user:view','#','admin',NULL,'admin',NULL,NULL)
,('⽤户查询',10,1,'#',30,10,'user:list','#','admin',NULL,'admin',NULL,NULL)
,('⽤户新增',10,2,'#',30,10,'user:add','#','admin',NULL,'admin',NULL,NULL)
,('⽤户修改',10,3,'#',30,10,'user:update','#','admin',NULL,'admin',NULL,NULL)
,('⽤户删除',10,4,'#',30,10,'user:delete','#','admin',NULL,'admin',NULL,NULL);
CREATE TABLE`sys_user_role`(
`id`bigint(20)unsigned NOT NULL AUTO_INCREMENT COMMENT'主键ID',
`user_id`bigint(20)unsigned NOT NULL COMMENT'⽤户ID',
`role_id`bigint(20)unsigned NOT NULL COMMENT'⾓⾊ID',
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=2DEFAULT CHARSET=utf8 COMMENT='⽤户⾓⾊表';
INSERT INTO sys_user_role (user_id,role_id)VALUES(1,1);
CREATE TABLE`sys_role_menu`(
`id`bigint(20)unsigned NOT NULL AUTO_INCREMENT COMMENT'主键ID',
`role_id`bigint(20)unsigned NOT NULL COMMENT'⾓⾊ID',
`menu_id`bigint(20)unsigned NOT NULL COMMENT'菜单ID',
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=7DEFAULT CHARSET=utf8 COMMENT='⾓⾊菜单表';
INSERT INTO sys_role_menu (role_id,menu_id)VALUES
(1,1),(1,10),(1,101),(1,102),(1,103),(1,104);
CREATE TABLE`persistent_logins`(
`username`varchar(64)NOT NULL,
`series`varchar(64)NOT NULL,
`token`varchar(64)NOT NULL,
`last_used`timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(`series`)
)ENGINE=InnoDB CHARACTER SET= utf8;
引⼊项⽬依赖
整合SpringSecurity核⼼的依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
配置⽂件
server:
port:8090
spring:
application:
name: springboot-security
datasource:
driver-class-name: sql.cj.jdbc.Driver
url: jdbc:mysql://192.168.108.11:3306/springboot?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serv erTimezone=GMT%2B8
username: root
password: root
hikari:
minimum-idle:10 #最⼩空闲连接,默认10
maximum-pool-size:20 #最⼤连接数
idle-timeout:600000 #空闲连接超时时间,默认600000(10分钟)
max-lifetime:540000 #连接最⼤存活时间,默认30分钟
connection-timeout:60000 #连接超时时间,默认30秒
connection-test-query: SELECT 1 #测试连接是否可⽤查询语句
type: com.zaxxer.hikari.HikariDataSource
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
thymeleaf:
mode: HTML
encoding: UTF-8
cache:false
resources:
static-locations: classpath:/templates/, classpath:/public/, classpath:/static/
mybatis-plus:
mapper-locations: classpath:mapper/**/*l
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-aliases-package: com.ity
logging:
config: l
level:
com.xlhj.security: debug
Spring Security关键配置类SecurityConfig代码如下:
@EnableGlobalMethodSecurity(prePostEnabled =true, securedEnabled =true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private DataSource dataSource;
@Resource
private SecurityAuthenticationFailureHandler authenticationFailureHandler;
@Resource
private AuthenticationEntryPointHandler authenticationEntryPoint;
@Resource
private SecurityAccessDeniedHandler accessDeniedHandler;
/**
* 配置密码解析
* @return
*/
@Bean
protected PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 配置⽤户名和密码
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth)throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http)throws Exception {
//关闭csrf防护
http.csrf().disable()
//表单登录
.formLogin()
/
/登录页⾯
.loginPage("/login.html")
//登录访问路径,与页⾯表单提交路径⼀致
.loginProcessingUrl("/login")
//登录成功后访问路径
.defaultSuccessUrl("/index.html").permitAll()
.failureHandler(authenticationFailureHandler)
.and()
//认证配置
.authorizeRequests()
.antMatchers("/login.html","/login").permitAll()
/
/配置静态页⾯可以访问
.antMatchers("/js/**","/css/**","/images/**","/favicon.ico").permitAll()
//任何请求
.anyRequest()
//都需要⾝份验证
.authenticated();
//配置⽆权限访问页⾯
//ptionHandling().accessDeniedPage("/uanuth.html");
//配置记住我
/
/持久层对象
.tokenRepository(persistentTokenRepository())
//失效时间(秒)
.tokenValiditySeconds(60)
//配置⾃定义登录逻辑
.userDetailsService(userDetailsService);
//配置退出
http.logout()
//退出路径
.logoutUrl("/logout")
//退出后跳转页⾯
.
logoutSuccessUrl("/login.html");
}
/**
* 配置记住我
* @return
*/
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository =new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
//jdbcTokenRepository.setCreateTableOnStartup(true);//请求时创建表
return jdbcTokenRepository;
}
}
⾃定义登录实现类

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。