SpringBoot整合SpringSecurity(附源码)
点击上方蓝色字体,选择“标星公众号”
优质文章,第一时间送达
在前几篇博客里,我们对于SpringBoot框架的项目中的认证还是采用最朴素的拦截器来实现的,那SpringBoot这么高级,就没有什么成熟的解决方案吗?有的,Spring Security,今天我们就来认识Spring Security,再配上一个demo加深理解。
Spring Security简介
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security
模块,进行少量的配置,即可实现强大的安全管理。
记住常用的几个类:
WebSecurityConfigurerAdapter
:自定义 Security 策略AuthenticationManagerBuilder
:自定义认证策略@EnableWebSecurity
:开启 WebSecurity 模式
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
“认证”(Authentication)
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
那实际上除了SpringSecurity,用的比较多的安全框架还有shiro。可以下宏观的了解一下
SpringSecurity和Shiro的相同点和不同点。
相同点
认证功能、授权功能、加密功能、会话管理、缓存支持、rememberMe功能
不同点
1、SpringSecurity基于Spring开发,项目中如果使用Spring作为基础,配合SpringSecurity做权限更加方便,而Shiro需要和Spring进行整合开发
2、SpringSecurity功能比Shiro更加丰富些,例如安全防护
3、SpringSecurity社区资源比Shiro丰富
4、Shiro配置和使用比较简单,SpringSecurity上手复杂
5、Shiro依赖性低,不需要任何框架和容器,可以独立运行,而SpringSecurity依赖于Spring容器。
测试Demo
前置准备
首先创建一个SpringBoot项目,勾选SpringSecurity模块
或者创建项目后导入依赖
org.springframework.boot
spring-boot-starter-security
为了方便前端展示,我们还导入thymeleaf依赖
创建几个前端页面(用于后面来测试权限访问)提取码:o9dz
项目结构如下图所示
测试主页及跳转(测试时先把SpringSecurity依赖注释掉)
编写基础配置类
在项目下创建config包,新建SecurityConfig.java
package com.feng.config;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* springsecurity-test
*
*
* @author : Nicer_feng
* @date : 2020-10-13 11:38
**/
@EnableWebSecurity //开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
// 首页所有人可以访问
// 其他界面只有对应的角色(权限)才可以访问
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
}
}
测试
开启后我们再测试下
可以发现报了403forbidden错误
There was an unexpected error (type=Forbidden, status=403).
Access Denied
我们在配置类中添加如未登录强制跳转到login页面
这里的http.formLogin();表示开启自动配置的登录功能,如果无权限则跳转到/login
测试发现确实如此,如果没有权限则强制跳转到登录页面
但需要注意的是,这个登录页面并不是我们自己写的login页面,而是SpringSecurity自带的默认登录页面
重写认证规则
我们可以自定义认证规则,重写configure(AuthenticationManagerBuilder auth)方法来配置认证的规则。
可以看到这里的认证规则常用的有这几种,这里先用inMemoryAuthentication(内存数据库)的来演示
添加配置代码
package com.feng.config;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* springsecurity-test
*
*
* @author : Nicer_feng
* @date : 2020-10-13 11:38
**/
@EnableWebSecurity //开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("feng").password("111111").roles("vip1")
.and()
.withUser("user").password("22222").roles("vip2")
.and()
.withUser("admin").password("000000")
.roles("vip1","vip2","vip3");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
http.formLogin();
}
}
我们添加了三个用户,分别拥有不同的权限,重启tomcat后测试
可以发现这里报了无id映射的错误,之所以报这个错是因为从前端传过来的密码需要进行加密,否则无法登陆,我们是用官方推荐的bcrypt加密方式
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("feng").password(new BCryptPasswordEncoder().encode("111111"))
.roles("vip1")
.and()
.withUser("user").password(new BCryptPasswordEncoder().encode("222222"))
.roles("vip2")
.and()
.withUser("admin").password(new BCryptPasswordEncoder().encode("000000"))
.roles("vip1","vip2","vip3");
}
重启测试
权限注销
在配置类中加入注销功能
@Override
protected void configure(HttpSecurity http) throws Exception {
......
//开启自动配置的注销的功能
// /logout 注销请求
http.logout();
}
在index页面添加logout注销功能
注意这里的默认提示中的/login和/logout都是SpringSecurity自带的默认界面
点击注销后,会返回登录界面
如果想要注销后仍然回到首页,可以在logout()后添加logoutSuccessUrl
http.logout().logoutSuccessUrl("/");
根据权限显示不同页面
上面我们设置了三个用户,拥有不同权限,在实际业务中,那能不能让拥有相应权限的用户只显示相应的界面呢?是可以做到的,我们需要利用thymeleaf 和SpringSecurity结合的功能
首先添加对应依赖
org.thymeleaf.extras
thymeleaf-extras-springsecurity5
3.0.4.RELEASE
修改前端的页面
头部命名空间改为
"en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
网页部分
"isAuthenticated()">
"item">
"address card icon">
用户名:"principal.username">
角色:"principal.authorities">
"isAuthenticated()">
"item" th:href="@{/logout}">
"address card icon"> 注销