@

本教程是基于SpringMVC而创建的,不适用于WebFlux。(如果你不知道这两者,可以忽略这句提示)

提出一个需求

所有的技术是为了解决实际问题而出现的,所以我们并不空谈,也不去讲那么多的概念。在这样一个系统中,有三个接口,需要授权给三种权限的人使用,如下表:

接口地址 需要的权限描述 可访问的权限组名称
visitor/main 不需要权限,也不用登录,谁都可以访问
admin/main 必须登录,只有管理员可以访问 ADMIN
user/main 必须登录,管理员和用户权限都能访问 USER和ADMIN

解决方案:

  • 在Controller中判断用户是否登录和用户的权限组判断是否可以访问

    这是最不现实的解决方案,可是我刚进公司时的项目就是这样设计的,当时我还觉得很高大尚呢。

  • 使用Web应用的三大组件中和过滤器(Filter)进行判断

    这是正解,SpringSecurity也正是用的这个原理。如果你的项目足够简单,建议你直接使用这种方式就可以了,并不需要集成SpringSecurity。这部分的示例在代码中有演示,自己下载代码查看即可。

  • 我们可以直接使用SpringSecurity框架来解决这个问题

使用SpringSecurity进行解决

​ 网上的教程那么多,但是讲的都不清不楚。所以,请仔细阅读下段这些话,这要比后边的代码重要。

​ SpringSecurity主要有两部分内容:

  • 认证 (你是谁,说白了就是一个用户登录的功能,帮我们验证用户名和密码)
  • 授权 (你能干什么,就是根据当前登录用户的权限,说明你能访问哪些接口,哪些不能访问。)

这里的登录是对于浏览器访问来说的,因为如果是前后端分离时,使用的是Token进行授权的,也可以理解为登录用户,这个后边会讲。这里只是为了知识的严谨性才提到了这点

SpringSecurity和SpringBoot结合

1. 首先在pom.xml中引入依赖:

<!-- 不用写版本,继承Springboot的版本-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 配置用户角色和接口的权限关系

是支持使用xml进行配置的,但是在SpringBoot中更建议使用Java注解配置

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 配置用户权限组和接口路径的关系
* 和一些其他配置
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 对请求进行验证
.antMatchers("/visitor/**").permitAll()
.antMatchers("/admin/**").hasRole("ROLE_ADMIN") // 必须有ADMIN权限
.antMatchers("/user/**").hasAnyRole("ROLE_USER", "ROLE_ADMIN") //有任意一种权限
.anyRequest() //任意请求(这里主要指方法)
.authenticated() //// 需要身份认证
.and() //表示一个配置的结束
.formLogin().permitAll() //开启SpringSecurity内置的表单登录,会提供一个/login接口
.and()
.logout().permitAll() //开启SpringSecurity内置的退出登录,会为我们提供一个/logout接口
.and()
.csrf().disable(); //关闭csrf跨站伪造请求
} }

上边的配置主要内容有两个:

  1. 配置访问三个接口(实际上不仅仅是3个,/**是泛指)需要的权限;
  2. 配置了使用SpringSecurity的内置/login和/loginout接口(这个是完全可以自定义的)
  3. 权限被拒绝后的返回结果也可以自定义,它当权限被拒绝后,会抛出异常

说明:

  1. 上边的配置中,其实就是调用http的这个对象的方法;
  2. 使用.and()只为了表示一上配置结束,并满足链式调用的要求,不然之前的对象可能并不能进行链式调用
  3. 这个配置在SpringBoot应用启动的时候就会调用,也就是会将这些配置加载进内存,当用户调用对应的接口的时候,就会判断它的角色是否可以调用这个接口,流程图如下(我觉得图要比文字更能说明过程):

3. 配置用户名和密码

​ 配置了上边的接口和用户权限角色的关系后,就是要配置我们的用户名和密码了。如果没有正确的用户名和密码,神仙也登录不上去。

​ 关于这个,网上的教程有各种各样的配置,其实就一个接口,我们只需要实现这个接口中的方法就可以了。接口代码如下:

package org.springframework.security.core.userdetails;

public interface UserDetailsService {
/**
* 在登录的时候,就会调用这个方法,它的返回结果是一个UserDetails接口类
*/
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

​ 来看一下这个接口,如果想扩展,可以自己写一个实现类,也可以使用SpringSecurity提供的实现

public interface UserDetails extends Serializable {
// 用户授权集合
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}

​ UserDetailsServicer接口的实现类

@Configuration
public class UserDetailsServiceImpl implements UserDetailsService {
/**
* 这个方法要返回一个UserDetails对象
* 其中包括用户名,密码,授权信息等
*
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/**
* 将我们的登录逻辑写在这里
* 我是直接在这里写的死代码,其实应该从数据库中根据用户名去查
*/
if (username == null) {
//返回null时,后边就会抛出异常,就会登录失败。但这个异常并不需要我们处理
return null;
}
if (username.equals("lyn4ever")) {
//这是构造用户权限组的代码
//但是这个权限上加了ROLE_前缀,而在之前的配置上却没有加。
//与其说这不好理解,倒不如说这是他设计上的一个小缺陷
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
List<SimpleGrantedAuthority> list = new ArrayList<>();
list.add(authority);
//这个user是UserDetails的一个实现类
//用户密码实际是lyn4ever,前边加{noop}是不让SpringSecurity对密码进行加密,使用明文和输入的登录密码比较
//如果不写{noop},它就会将表表单密码进行加密,然后和这个对比
User user = new User("lyn4ever", "{noop}lyn4ever", list);
return user;
}
if (username.equals("admin")) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
SimpleGrantedAuthority authority1 = new SimpleGrantedAuthority("ROLE_ADMIN");
List<SimpleGrantedAuthority> list = new ArrayList<>();
list.add(authority);
list.add(authority1);
User user = new User("admiin", "{noop}admin", list);
return user;
} //其他返回null
return null;
}
}

4.进行测试

​ 分别访问上边三个接口,可以看到访问结果和上边的流程是一样的。

总结:

  • 仔细阅读上边的那个流程图,是理解SpringSecurity最重要的内容,代码啥的都很简单;上边也就两个类,一个配置接口与角色的关系,一个实现了UserDetailsService类中的方法。
  • 前边说了,SpringSecurity主要就是两个逻辑:
    • 用户登录后,将用户的角色信息保存在服务器(session中);
    • 用户访问接口后,从session中取出用户信息,然后和配置的角色和权限进行比对是否有这个权限访问
  • 上述方法中,我们只重写了用户登录时的逻辑。而根据访问接口来判断当前用户是否拥有这个接口的访问权限部分,我们并没有进行修改。所以这只适用于可以使用session的项目中。
  • 对于前后端分离的项目,一般是利用JWT进行授权的,所以它的主要内容就在判断token中的信息是否有访问这个接口的权限,而并不在用户登录这一部分。
  • 解决访问的方案有很多种,选择自己最适合自己的才是最好了。SpringSecurity只是提供了一系列的接口,他自己内部也有一些实现,你也可以直接使用。
  • 上边配置和用户登录逻辑部分的内容是完全可以从数据库中查询出来进行配置的。

代码地址

在SpringBoot中使用SpringSecurity的更多相关文章

  1. 在SpringBoot中对SpringSecurity的基本使用

    参考文献: Spring Security Architecture What is authentication in Spring Security? Spring Security是一个能够为基 ...

  2. 记录一下在SpringBoot中实现简单的登录认证

    代码参考博客: https://blog.csdn.net/weixin_37891479/article/details/79527641 在做学校的课设的时候,发现了安全的问题,就不怀好意的用户有 ...

  3. springboot+mybatis+SpringSecurity 实现用户角色数据库管理(一)

    本文使用springboot+mybatis+SpringSecurity 实现用户权限数据库管理 实现用户和角色用数据库存储,而资源(url)和权限的对应采用硬编码配置. 也就是角色可以访问的权限通 ...

  4. SpringBoot中yaml配置对象

    转载请在页首注明作者与出处 一:前言 YAML可以代替传统的xx.properties文件,但是它支持声明map,数组,list,字符串,boolean值,数值,NULL,日期,基本满足开发过程中的所 ...

  5. 如何在SpringBoot中使用JSP ?但强烈不推荐,果断改Themeleaf吧

    做WEB项目,一定都用过JSP这个大牌.Spring MVC里面也可以很方便的将JSP与一个View关联起来,使用还是非常方便的.当你从一个传统的Spring MVC项目转入一个Spring Boot ...

  6. springboot中swaggerUI的使用

    demo地址:demo-swagger-springboot springboot中swaggerUI的使用 1.pom文件中添加swagger依赖 2.从github项目中下载swaggerUI 然 ...

  7. spring-boot+mybatis开发实战:如何在spring-boot中使用myabtis持久层框架

    前言: 本项目基于maven构建,使用mybatis-spring-boot作为spring-boot项目的持久层框架 spring-boot中使用mybatis持久层框架与原spring项目使用方式 ...

  8. 由浅入深学习springboot中使用redis

    很多时候,我们会在springboot中配置redis,但是就那么几个配置就配好了,没办法知道为什么,这里就详细的讲解一下 这里假设已经成功创建了一个springboot项目. redis连接工厂类 ...

  9. Springboot中使用AOP统一处理Web请求日志

    title: Springboot中使用AOP统一处理Web请求日志 date: 2017-04-26 16:30:48 tags: ['Spring Boot','AOP'] categories: ...

随机推荐

  1. .net 4.0 以下HttpWebRequest Header 修改hosts方法

    .net 4.0 以下HttpWebRequest Header 修改hosts方法 特此记录 public class CusteredHeaderCollection : WebHeaderCol ...

  2. 《Python学习手册 第五版》 -第15章 文档

    本章主要介绍Python中的文档,会通过多种方式来说明,如果查看Python自带文档和其他参考的资料 本章重点内容 1.#注释:源文件文档 2.dir函数:以列表显示对象中可用的属性 3.文档字符串 ...

  3. mysql数据库设计文档-导出字段设计

    navicat 是我一直在使用的一个数据库操作工具,非常方便快捷.如果没有可用navicat可以留言邮箱我直接发您. 今天来介绍一下使用navicat导出数据库字段设计.废话不多说,先看导出效果. 查 ...

  4. 三万字、91道MySQL面试题。 附PDF

    文末领取面试题 高清PDF 数据库基础知识 1. 为什么要使用数据库 数据保存在内存 优点:存取速度快 缺点:数据不能永久保存 数据保存在文件 优点:数据永久保存 缺点:1)速度比内存操作慢,频繁的I ...

  5. mysql 更换数据目录

    mysql 更换数据目录 1.停止MySql服务: /etc/rc.d/init.d/mysql stop 或者 service mysql stop 2.确认MySql原来的数据目录,查找datad ...

  6. 二维数组及Arrays工具类

    1.二维数组 概念: 数组中的每一个元素类型都是一维数组 二维数组初始化方式: 静态初始化: 格式: 元素类型[][] 数组名 = new 元素类型[][]{{一维数组1},{一维数组2},{一维数组 ...

  7. thinkphp5.0.*命令执行批量脚本

    import requests import Queue import threading import time user_agent = "Mozilla/5.0 (Windows NT ...

  8. vue项目创建与使用

    目录 复习 Vue项目环境搭建 Vue项目创建 pycharm配置并启动vue项目 vue项目目录结构分析 vue组件(.vue文件) 全局脚本文件main.js(项目入口) 改写 vue项目启动生命 ...

  9. Windows下利用Chrome调试IOS设备页面

    本文介绍如何在 Windows 系统中连接 iOS设备 并对 Web 页面进行真机调试 必须前提 iOS设备.数据线 Node.js 环境 Chrome 浏览器 环境准备 安装Node环境 参考Nod ...

  10. hdu3695 AC自动机优化

    题目链接:http://icpc.njust.edu.cn/Problem/Hdu/3695/ 不加last指针的AC自动机会T,原因是他费了很多功夫在跳转上,而last指针是直接直到跳转的终止位置, ...