SpringBoot--- 使用SpringSecurity进行授权认证

前言

在未接触 SpringSecurity 、Shiro 等安全认证框架之前,如果有页面权限需求需要满足,通常可以用拦截器,过滤器来实现。

但是,这需要大量配置类去完成,代码编写工作量是巨大的。为提高工作效率,学习SpringSecurity 等框架变得十分必要。

环境

IDEA :2020.1

Maven:3.5.6

SpringBoot: 2.3.2

MySQL 8.0

1、导入正确的依赖

重要依赖

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

也可以在构建工程师勾选

另外,笔者使用的模板引擎是 Thymeleaf ,因此也需要导入该依赖,不适用该模板引擎的不需要导入该依赖。

<!--       thymeleaf-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

2、编写或导入页面素材,HTML页面等

读者可以自行编写,除了login 页面必须要有 form 表单提交,以便处理登录请求外,其他页面可根据需要编写。

关于页面,登录提交表单有一个注意事项

<form class="form-signin" method="post" action="/login">

一般提交表单,这样写是没有问题的,但是,我们添加了 spring-boot-starter-security 依赖,使用了SpringSecurity ,提交所有表单(包括这次的登录表单),都会交由SpringSecurity 处理。

SpringSecurity 默认开启了防止跨域攻击的功能,任何 POST 提交到后台的表单都要验证是否带有 _csrf 参数,一旦传来的 _csrf 参数不正确,服务器便返回 403 错误;

上述写法,我们可以访问后,在调试模式查看元素。

是没有 _csrf 参数的,这样提交的时候将会被拦截。

提交表单403解决方法

1、直接关闭防止域攻击功能。(可以在下面介绍到的配置类中使用)
http.csrf().disable()

这样的做法是不建议的,安全级别会降低。有违使用 SpringSecurity 的初衷。

2、使用 Thymeleaf 在 form 表单添加 th:action 元素,Thymeleaf 会自动为我们添加 _csrf 元素。
<form class="form-signin" method="post" th:action="@{/login}">

3、在 form 表单中手动添加隐藏 _csrf

在 form 表单中手动添加隐藏 _csrf,比较麻烦,这里不做过多介绍。都用SpringBoot 了,还手动配置这么多,这不有违初衷了吗?当然,感兴趣的可以自己摸索。

3、测试环境,保证页面访问成功

这里要做的是编写一个 Controller 类

@Controller
public class RouterController {
@RequestMapping( {"/","/index"} )
public String index(){
return "welcome";
} @RequestMapping("/toLogin")
public String toLogin(){
return "pages/login";
} @RequestMapping("/level1/{id}")
public String toLevel1(@PathVariable("id") int id){
return "pages/level1/"+ id;
} @RequestMapping("/level2/{id}")
public String toLevel2(@PathVariable("id") int id){
return "pages/level2/"+ id;
}
@RequestMapping("/level3/{id}")
public String toLevel3(@PathVariable("id") int id){
return "pages/level3/"+ id;
}
}

启动程序,访问页面。当然,测试之前,我们需要把 SpringSecurity 的依赖导入暂时注释掉,否则,SpringSecurity 将会拦截下我们的请求。

访问成功,页面是没有问题的。这样做有利于我们后面出问题时,排查问题,并非多此一举。类似于断点Debug ,相当于我们在这一阶段前的工作是无误的。问题出现应该在这一断点(阶段)后排查。

别忘了,注释掉的SpringSecurity ,我们要解除掉注释。

4、配置用户,权限

1、yml

spring:
security:
user:
name: tom001
password: 1234
roles: [level1,level2]

这样就可以配置用户名,密码和权限了,太方便了吧!

但是,却只能添加一个用户,因为user,password 等属性都只是String类型的,只有roles 才是List 类型的。笔者内问百度博客,外问谷歌,Stack Overflow 都没有找到SpringSecurity可以在yml配置文件下配置多用户的方法。如果你知道,请评论留言告诉我,小弟谢过了。

2、配置类

所以最后还是回到配置类上来吧,很多问题还可以从官方和源码中找到正确的配置方法。(虽然不能用 yml 提【tou】高【gong】效【jian】率【liao】了 T_T )

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//定义访问权限规则
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("level1")
.antMatchers("/level2/**").hasRole("level2")
.antMatchers("/level3/**").hasRole("level3");
//没有权限将跳转到登录页面
http.formLogin();
}
}

很遗憾,主页依然可以访问,在访问需要权限的页面时候,被服务器拒绝访问(403 表示服务器拒绝该访问请求)。

http.formLogin();

上面这个方法值得我们来分析一下,因为我们 Controller 配置的并没有 login 而是 toLogin 。

    @RequestMapping("/toLogin")
public String toLogin(){
return "pages/login";
}

SpringSecurity 是如何帮我们自动配置的呢?

我们去到 formLogin() 方法即可一探究竟。

	 * Specifies to support form based authentication. If
* {@link FormLoginConfigurer#loginPage(String)} is not specified a default login page
* will be generated.
*
* <h2>Example Configurations</h2>
*
* The most basic configuration defaults to automatically generating a login page at
* the URL "/login", redirecting to "/login?error" for authentication failure. The
* details of the login page can be found on
* {@link FormLoginConfigurer#loginPage(String)}
*

在方法体上,找到了注释。请特别注意以下这句话:

The most basic configuration defaults to automatically generating a login page at

the URL "/login", redirecting to "/login?error" for authentication failure.

默认情况下,最基本的配置是在URL“ /login”处自动生成一个登录页面,并重定向到“ /login?error”来进行身份验证失败。

而且,调转到的 /login ,并不是我们编写的 login.html 页面,而是由 SpringSecurity 提供的登录页面。

这里跳转了很久,难道是 SpringSecurity 在后天写页面?哈哈

我们可以点进查看一下 formLogin() 方法

	 * 	@Override
* protected void configure(HttpSecurity http) throws Exception {
* http.authorizeRequests().antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().formLogin()
* .usernameParameter(&quot;username&quot;) // default is username
* .passwordParameter(&quot;password&quot;) // default is password
* .loginPage(&quot;/authentication/login&quot;) // default is /login with an HTTP get
* .failureUrl(&quot;/authentication/login?failed&quot;) // default is /login?error
* .loginProcessingUrl(&quot;/authentication/login/process&quot;); // default is /login
* // with an HTTP
* // post

原来,我们可以指定登录页面,SpringSecurity 会帮助我们跳转过去。

.formLogin().loginPage("/toLogin");

这下帮刘都统接上了腿,一下子就可跳过去了吧?哈哈哈


接下来就是认证方面的工作了。我们需要编写的类可以通过查看,需要重写哪些类,它的参数一般可以标明他要做的配置工作。

既然是配置,那自然是 configure 方法,我们可以去查看下图所示的这一 configure方法。

在源码,我们发现框架开发者在方法的注释上,贴心地为我们写好了配置示例。

	 * @Override
* protected void configure(AuthenticationManagerBuilder auth) {
* auth
* // enable in memory based authentication with a user named
* // &quot;user&quot; and &quot;admin&quot;
* .inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;).and()
* .withUser(&quot;admin&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;, &quot;ADMIN&quot;);
* }

我们按照他说要求的配置如下:

    //认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("tom001").password("1234").roles("level1","level3");
}

哈哈,终于要完成了,我们来验证一下吧!

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

密码没有编码?啥意思?

都说了是 SpringSecurity,登录密码还是明文密码,那还了得?人家一个反编译,你岂不是底裤都让人看光了?

但是官方一句提醒都没有,啊,这......

确实有点麻烦,但是我们的目的是让它起作用,还是找找方法吧。

    //认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("tom001").password(new BCryptPasswordEncoder().encode("1234")).roles("level1","level3");
}

最后加上加密类,这次总该成了吧?

成功了!


实际使用中,还是要结合数据库获取用户密码,权限等信息的。

SpringBoot--- 使用SpringSecurity进行授权认证的更多相关文章

  1. SpringBoot整合SpringSecurity实现JWT认证

    目录 前言 目录 1.创建SpringBoot工程 2.导入SpringSecurity与JWT的相关依赖 3.定义SpringSecurity需要的基础处理类 4. 构建JWT token工具类 5 ...

  2. 使用SpringSecurity搭建授权认证服务(1) -- 基本demo认证原理

    使用SpringSecurity搭建授权认证服务(1) -- 基本demo 登录认证是做后台开发的最基本的能力,初学就知道一个interceptor或者filter拦截所有请求,然后判断参数是否合理, ...

  3. 用JWT技术为SpringBoot的API增加授权保护(转),需要自己实现userdetailservice接口

    转自:https://blog.csdn.net/haiyan_qi/article/details/77373900 概述 示例 https://github.com/qihaiyan/jwt-bo ...

  4. 【使用篇二】SpringBoot集成SpringSecurity(22)

    SpringSecurity是专门针对基于Spring项目的安全框架,充分利用了依赖注入和AOP来实现安全管控.在很多大型企业级系统中权限是最核心的部分,一个系统的好与坏全都在于权限管控是否灵活,是否 ...

  5. SpringBoot 集成SpringSecurity JWT

    目录 1. 简介 1.1 SpringSecurity 1.2 OAuth2 1.3 JWT 2. SpringBoot 集成 SpringSecurity 2.1 导入Spring Security ...

  6. SpringSecurity之授权

    SpringSecurity之授权 目录 SpringSecurity之授权 1. 写在前面的话 2. web授权 1. 建库 2. 添加查询权限的接口 3. 前端页面的编写 4. SpringSec ...

  7. SpringBoot整合SpringSecurity示例实现前后分离权限注解

    SpringBoot 整合SpringSecurity示例实现前后分离权限注解+JWT登录认证 作者:Sans_ juejin.im/post/5da82f066fb9a04e2a73daec 一.说 ...

  8. 9、SpringBoot整合之SpringBoot整合SpringSecurity

    SpringBoot整合SpringSecurity 一.创建项目,选择依赖 选择Spring Web.Thymeleaf即可 二.在pom文件中导入相关依赖 <!-- 导入SpringSecu ...

  9. SpringSecurity个性化用户认证流程

    ⒈自定义登录页面 package cn.coreqi.security.config; import org.springframework.context.annotation.Bean; impo ...

随机推荐

  1. ElasticSearch(二)Kibana、版本控制

    Kibana简介: Kibana可视化界面 Kibana是一个开源的分析和可视化平台,设计用于和Elasticsearch一起工作. 你用Kibana来搜索,查看,并和存储在Elasticsearch ...

  2. 一个使用android相机的例子,二维码必须用相机

    https://blog.csdn.net/feiduclear_up/article/details/51968975

  3. python从放弃到放弃

    本文目录 第一篇:python基础 第二篇:数据类型 第三篇:文件处理 第四篇:函数 第五篇:模块与包 第六篇:常用模块

  4. state实例

    States是SaltStack中的配置语言,在日常进行配置管理时需要编写大量的States文件. 比如我们需要安装一个包,然后管理一个配置文件,最后保证某个服务正常运行. 这里就需要我们编写一些st ...

  5. 萌新学渗透系列之Hack The Box_Lame

    我将我的walkthrough过程用视频解说的形式记载 视频地址https://www.bilibili.com/video/BV1Mv411z75c 一是因为看我视频的后来者应该都是刚入门的新手,视 ...

  6. 修改git上传代码的作者姓名

    本文参考https://www.cnblogs.com/weiaiqi/p/11842515.html 随着IT行业的不断壮大,开源的东西越来越多,使用git来进行代码管理的人自然也越来越多,而且很多 ...

  7. Python os.read() 方法

    概述 os.read() 方法用于从文件描述符 fd 中读取最多 n 个字节,返回包含读取字节的字符串,文件描述符 fd对应文件已达到结尾, 返回一个空字符串.高佣联盟 www.cgewang.com ...

  8. Python os.mkdir() 方法

    概述 os.mkdir() 方法用于以数字权限模式创建目录.默认的模式为 0777 (八进制).高佣联盟 www.cgewang.com 语法 mkdir()方法语法格式如下: os.mkdir(pa ...

  9. PHP imagechar - 写出横向字符

    imagechar — 写出横向的字符.高佣联盟 www.cgewang.com 语法 bool imagechar ( resource $image , int $font , int $x , ...

  10. PHP zip_open() 函数

    定义和用法 zip_open() 函数打开 zip 档案以供读取.高佣联盟 www.cgewang.com 如果成功,该函数则返回 zip 文件资源.如果失败,则返回 FALSE. 语法 zip_op ...