个人博客网:https://wushaopei.github.io/    (你想要这里多有)

1、Spring Security 权限管理框架介绍

简介: Spring Security 提供了基于javaEE的企业应有个你软件全面的安全服务。这里特别强调支持使用SPring框架构件的项目,Spring框架是企业软件开发javaEE方案的领导者。

Spring Security 的两个目标: “认证” 与“授权”。

  • 认证”,是建立一个他声明的主题的过程(一个“主体”一般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统)。
  • 授权” 指确定一个主体是否允许在你的应用程序执行一个动作的过程。为了抵达需要授权的店,主体的身份已经有认证过程建立。这个概念是通用的而不只在Spring Security中。

在SpringSecurity 中,请求进入后会被拦截器拦截到,并交由认证管理器首先处理;这是在身份验证层,Spring Security 的支持多种认证模式。包括 Basic、Digest、X.509、LDAP、Form(基于表单的认证) 等多种HTTP 认证。

浅析:

Basic 认证:在HTTP1.0提出的认证方法,针对特定的用户和资源,需要提供特定的密码认证后方可访问,其中密码是使用明文传输的;一个请求到来时,浏览器弹出对话框,让用户输入用户名和密码,并用BASE 64 进行编码进行传输,服务器接受并解析这些信息,并认证通过,才会允许继续访问。

Digest认证: 解决Basic 认证的安全问题,当访问时,浏览器依旧弹出对话框,让用户输入用户名和密码,浏览器会对用户名、密码、HTTP请求方法、被请求资源的URI进行组合后进行MD5运算,然后把计算得到的摘要信息发送给服务器;服务器获取报文头部相关认证信息后获取到 username ,同时获取到密码,同样对用户名、密码、HTTP请求方法、被请求资源的URI进行组合后和 response 进行比较,如果相同,才算认证通过。

2、Spring Security 常用权限拦截器:

主要功能性拦截器有 11 个, FilterChainProxy 对拦截器进行过滤操作并代理执行!

3、Spring Security 项目 Demo

(1)环境搭建及使用

  1. 基于Spring Boot + Spring Security 环境
  2. 常用 Case 实现

(2)创建SpringBoot 工程

(3)整合SpringSecurity 依赖

	        <!--springsecurity 主要依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>

(4)主启动类配置:

@RestController          //返回响应体为json
@SpringBootApplication
@EnableAutoConfiguration //扫描Bean注入到容器中
public class Bootstrap { public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
} @RequestMapping("/") // 测试接口
public String home (){
return "hello spring boot";
} @RequestMapping("/hello") //测试接口
public String hello (){
return "hello spring boot";
}
}

(5)配置 Servlet 初始化

/**
* @ClassName ServletInitializer 告诉程序,项目启动时从 Bootstrap 开始
* @Description TODO
* @Author wushaopei
* @Date 2019/9/19 10:30
* @Version 1.0
*/
public class ServletInitializer extends SpringBootServletInitializer { @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application){
return application.sources(Bootstrap.class);
}
}

(6)启动SpringBoot 项目- - run 主启动类:

启动SpringBoot 项目进行接口访问时,弹出登录界面,说明SpringSecurity生效了

4、SpringSecurity拦截配置:

注意:在 3  的基础上,对工程进一步配置:

(1)创建 SpringSecurityConfig 类管理 拦截配置:

@Configuration     // 将Bean 放到容器中管理
@EnableWebSecurity // 用于将Security 生成 Bean
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { /*
* 接口请求拦截
**/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //安全请求策略
.antMatchers("/").permitAll() //可放行请求配置
.anyRequest().authenticated() //其他请求进行拦截
.and()
.logout().permitAll() // 注销任意访问
.and()
.formLogin();
http.cors().disable();
}
/*
* 前端拦截
* */
@Override
public void configure(WebSecurity web){
// 忽视 js 、css 、 images 后缀访问
web.ignoring().antMatchers("/js/**","/css/**","/images/**");
}
}

该 SpringSecurityConfig 继承 WebSecurityConfigurerAdapter 类,并重写 configure(HttpSecurity http)和 configure(WebSecurity web)两个方法,分别针对 接口请求 静态页面 资源进行拦截。

接口请求: ip:port/  的请求一律通过,主要进入到 Bootstrap 中的 RequestMapping(“/”)接口中;并对 “/”后带有标识地址的请求进行拦截认证;

静态资源: 此处对静态 js 、css、images 三者进行放行。

效果截图:

配置 SpringSecurity 后,默认可以通过 “/” 的接口请求; 而当进行 如“/hello”接口请求时会被拦截进行验证

5、基于SpringSecurity 权限管理 Case 实操

权限管理 Case 的需求有两个要求:

  1. 第一点 :只要能登录即可;
  2. 第二点:有指定的角色,每个角色有指定的权限.

(1)只要能登录即可,功能体现:

在SpringSecurityConfig.java中配置用户信息:

/*
* 告诉程序,系统中有个用户 用户名为 admin ,密码为 admin 角色为 ADMIN
* */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN"); }

注意 :

在springboot使用spring security 做权限管理 ,使用内存用户验证,会返回无响应报错:
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

解决方法:

这是因为Spring boot 2.0.3引用的security 依赖是 spring security 5.X版本,此版本需要提供一个PasswordEncorder的实例,否则后台汇报错误:

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
并且页面毫无响应。
因此,需要创建PasswordEncorder的实现类。

创建PasswordEncorder 实体类后可通过两种方式完成明文验证通过:

第一种:直接在配置好的 PasswordEncorder 类上添加 @Component 装配 MyPasswordEncoder 为Bean 注入到容器即可;

@Component
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
} @Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
}

然后继续使用

  /*
* 告诉程序,系统中有个用户 用户名为 admin ,密码为 admin 角色为 ADMIN
* */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception { //可以设置内存指定的登录的账号密码,指定角色
//不加.passwordEncoder(new MyPasswordEncoder())或者注入该类的Bean
//就不是以明文的方式进行匹配,会报错
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
}

进行 密码明文登录,可以成功

第二种:在auth.inMemoryAuthentication()后面使用.passwordEncoder(new MyPasswordEncoder())对登录信息进行包装后提交即可;这样也可以成功

//这样,页面提交时候,密码以明文的方式进行匹配。
auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder()).withUser("wsp").password("wsp").roles("ADMIN");

推荐: 最好是使用第一种 装载成 Bean 后注入容器,对于开发效率更高,也更便捷。

(2)有指定的角色,每个角色有指定的权限,功能体现:

① 创建接口 role1() 并对其添加 @PreAuthorize("hasRole('ROLE_ADMIN')")  以进行角色拦截

    @PreAuthorize("hasRole('ROLE_ADMIN')") // 角色拦截校验注解
@RequestMapping("/roleAuth")
public String role1(){ return "roleAuth";
}

(2)角色拦截 - - 功能解析:

@PreAuthorize("hasRole('ROLE_ADMIN')") 注解说明:

②并在 SpringSecurityConfig.java 中创建新用户,以提供测试:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//可以设置内存指定的登录的账号密码,指定角色
//不加.passwordEncoder(new MyPasswordEncoder())
//就不是以明文的方式进行匹配,会报错
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
auth.inMemoryAuthentication().withUser("demo").password("demo").roles("DEMO");
.passwordEncoder(new MyPasswordEncoder())。
//这样,页面提交时候,密码以明文的方式进行匹配。
auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder()).withUser("wsp").password("wsp").roles("ADMIN");
}

③ 创建好接口后,进行登录尝试,发现,使用 用户为 demo ,角色 为 DEMO 依旧可以通过该接口

问题解析:

这是因为还需要再添加一个@EnableGlobalMethodSecurity(prePostEnabled = true) 注解到 启动器上,以让 @PreAuthorize("hasRole('ROLE_ADMIN')") 这个注解生效,完整 启动类代码如下:

@RestController
@SpringBootApplication
@EnableAutoConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class Bootstrap { public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
@RequestMapping("/")
public String home (){
return "hello spring boot";
}
@RequestMapping("/hello")
public String hello (){
return "hello spring boot";
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping("/roleAuth")
public String role1(){
return "roleAuth";
}
}

添加注解后

使用 demo 进行登录:

使用admin进行登录:

(3)数据库管理实现

通过数据库获取用户信息进行登录认证

创建 MyUserService.java类,并装载 Bean 到 容器中,在SpringSecurityConfig.java 中进行配置:

@Component
public class MyUserService implements UserDetailsService{
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return null;
}
}

SpringSecurityConfig.java 中 configure(AuthenticationManagerBuilder auth)方法修改为通过注入MyUserService 的Bean实现数据库查询

    @Autowired
private MyUserService myUserService; @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserService); // 通过注入 MyUserService 的方式实现数据库查询用户信息的登录认证 }

密码的自定义验证:

创建 MyPasswordEncoder 类,实现 PasswordEncoder 接口类;重写 encode(CharSequence obj和 matches(CharSequence obj,String str) 方法:

@Component
public class MyPasswordEncoder implements PasswordEncoder { private final static String SALT = "wenmin"; @Override
public String encode(CharSequence charSequence) { return MD5Util.MD5Encode(charSequence.toString(),SALT);
} @Override
public boolean matches(CharSequence rawPassword, String encodedPassword) { return MD5Util.isPasswordValid(encodedPassword,rawPassword.toString(),SALT);
}
}

说明:第一个是加密的方法,第二个是匹配密码,具体操作是加密方法加密后与原始密码在匹配方法中进行匹配

底层逻辑解析:

passwordEncoder. isPasswordValid(userDetails.getPassword(), presentedPassword, salt) 这个实现是在接口PasswordEncoder的实现类MessageDigestPasswordEncoder中实现的。 

MessageDigestPasswordEncoder类:
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
String pass1 = "" + encPass;
String pass2 = encodePassword(rawPass, salt); return pass1.equals(pass2);
} 其中 encodePassword(rawPass, salt)方法如下:
public String encodePassword(String rawPass, Object salt) {
String saltedPass = mergePasswordAndSalt(rawPass, salt, false); MessageDigest messageDigest = getMessageDigest(); byte[] digest; try {
digest = messageDigest.digest(saltedPass.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 not supported!");
} // "stretch" the encoded value if configured to do so
for (int i = 1; i < iterations; i++) {
digest = messageDigest.digest(digest);
} if (getEncodeHashAsBase64()) {
return new String(Base64.encode(digest));
} else {
return new String(Hex.encode(digest));
}
}
使用的是MD5加密方法。

引入自定义的登录信息验证器

auth.userDetailsService(myUserService).passwordEncoder(new MyPasswordEncoder());

相关注解说明:

@PreAuthorize("hasRole('ROLE_ADMIN')")  方法调用前进行权限检查
@PostAuthorize("hasRole('')")           方法调用后进行权限检查
@PreFilter("")                          方法调用前针对集合类参数或返回值进行过滤
@PostFilter("") 方法调用后针对集合类参数或返回值进行过滤

6、Spring Security 的优缺点

优点:

提供了一套安全框架,而且这个框架是可以用的;

提供了很多用户认证的功能,实现相关接口即可,节约大量开发工作;

基于spring,易于集成到 spring 项目中,且封装了许多方法。

缺点:

配置文件多,角色被“编码”到配置文件盒源文件中,RBAC 不明显;

对于系统中用户、角色、权限之间的关系,没有可操作的界面;

大数据量情况下,几乎不可用。

https://github.com/wushaopei/SPRING_BOOT/tree/master/Spring-boot-Security

快速搭建基于Spring Boot + Spring Security 环境的更多相关文章

  1. 如何快速搭建基于python+appium的自动化测试环境

    首先申明本文是基本于Python与Android来快速搭建Appium自动化测试环境: 主要分为以下几个步骤: 前提条件: 1)安装与配置python环境,打开 Python官网,找到“Downloa ...

  2. 快速搭建Spring Boot + Apache Shiro 环境

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.Apache Shiro 介绍及概念 概念:Apache Shiro是一个强大且易用的Java安全框 ...

  3. 基于Spring Boot+Spring Security+JWT+Vue前后端分离的开源项目

    一.前言 最近整合Spring Boot+Spring Security+JWT+Vue 完成了一套前后端分离的基础项目,这里把它开源出来分享给有需要的小伙伴们 功能很简单,单点登录,前后端动态权限配 ...

  4. 256.Spring Boot+Spring Security: MD5是加密算法吗?

    说明 (1)JDK版本:1.8 (2)Spring Boot 2.0.6 (3)Spring Security 5.0.9 (4)Spring Data JPA 2.0.11.RELEASE (5)h ...

  5. 255.Spring Boot+Spring Security:使用md5加密

    说明 (1)JDK版本:1.8 (2)Spring Boot 2.0.6 (3)Spring Security 5.0.9 (4)Spring Data JPA 2.0.11.RELEASE (5)h ...

  6. Spring Boot+Spring Security:获取用户信息和session并发控制

    说明 (1)JDK版本:1.8(2)Spring Boot 2.0.6(3)Spring Security 5.0.9(4)Spring Data JPA 2.0.11.RELEASE(5)hiber ...

  7. Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(一)

    标题 Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(一) 技术 Spring Boot 2.Spring Security 5.JWT 运行环境 ...

  8. Spring boot +Spring Security + Thymeleaf 认证失败返回错误信息

    [Please make sure to select the branch corresponding to the version of Thymeleaf you are using] Stat ...

  9. Cola Cloud 基于 Spring Boot, Spring Cloud 构建微服务架构企业级开发平台

    Cola Cloud 基于 Spring Boot, Spring Cloud 构建微服务架构企业级开发平台: https://gitee.com/leecho/cola-cloud

随机推荐

  1. 修改MySQL表中的字段属性

    登录数据库 >mysql -u root -p 数据库名称 查询所有数据表 mysql>show tables; 查询表的字段信息 mysql>desc 表名称; 1.修改某个表的字 ...

  2. js基石之---es7的decorator修饰器

    es7的decorator修饰器 装饰器(Decorator)是一种与类(class)相关的语法,用来注释或修改类和类方法. decorator就是给类添加或修改类的变量与方法的. 装饰器是一种函数, ...

  3. 【Spark】使用java语言开发spark程序

    目录 步骤 一.创建maven工程,导入jar包 二.开发代码 步骤 一.创建maven工程,导入jar包 <properties> <scala.version>2.11.8 ...

  4. 并发工具类——Semaphore

    本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 Semaphore([' seməf :(r)])的主要 ...

  5. BIO、NIO、AIO的形象比喻

    BIO (Blocking I/O):同步阻塞I/O模式. NIO (New I/O):同步非阻塞模式. AIO (Asynchronous I/O):异步非阻塞I/O模型. 先看阻塞和非阻塞的区别, ...

  6. 设计模式之GOF23代理模式01

    代理模式 核心作用: -通过代理,控制对对象的访问 -可以详细控制机制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做 后置处理(AOP的微观实现) 应用场景 -安全代理:屏蔽 ...

  7. burpsuite抓包无法识别POST参数问题

    直接拿一道bugkuctf中的题目进行测试 这道题目就是用POST方法上传what=flag 我们利用burpsuite进制抓包 需要更改三个部分,这样就可以解决burpsuite无法识别POST参数 ...

  8. 08JAVA基础关键字(final、static)以及抽象类和接口

    一.关键字 1.final 修饰类 修饰变量 修饰成员方法 该类为最终类,不能被继承 该变量为常量 该成员方法不能被重写 2.static (1).生命周期 随着类的加载而加载 (2).特点 被本类所 ...

  9. Springboot中修改.properties文件为.yml文件时项目不能运行问题

    可能很多小伙伴会考虑环境配置的问题,maven版本.idea版本什么的,其实没有必要 只要你之前.ies时能运行,那么环境配置就没有问题 不能运行的原因,一定是你的.yml文件的格式问题 .yml文件 ...

  10. iOS中的系统目录(Documents、tmp、Library)、RunLoop的一些知识点

    学习内容 欢迎关注我的iOS学习总结--每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary 实现轮播图需要注意的地方 需要 ...