SpringSecurity

一、SpringSecurity介绍

1、介绍

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的事实上的标准。
Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。像所有Spring项目一样,Spring Security的真正强大之处在于它可以轻松扩展以满足定制需求的能力。
主要功能:
1、认证 (你是谁)
2、授权 (你能干什么)
3、攻击防护 (防止伪造身份)

2、特征

对身份验证和授权的全面且可扩展的支持

保护免受会话固定,点击劫持,跨站点请求伪造等攻击

Servlet API集成

与Spring Web MVC的可选集成

多得多…

3、使用条件

j8以上

二、SpringSecurity使用

1、导包

maven


    org.springframework.boot
    spring-boot-starter-security

gradle

dependencies {
    compile "org.springframework.boot:spring-boot-starter-security"
}

2、继承WebSecurityConfigurerAdapter开始操作

(1)、重写configure方法

简单整理下为什么开启跨域

如果没有同源策略,不同源的数据和资源(如HTTP头、Cookie、DOM、localStorage等)就能相互随意访问,根本没有隐私和安全可言。为了安全起见和资源的有效管理,浏览器当然要采用这种策略。

@Component
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       //开启跨域
        http.formLogin().and().cors().and().
                //后面都是授权配置
                authorizeRequests()
                //匹配    许可证 (该请求放行)
                .antMatchers("/demoController").permitAll()
                //或者除了放行的url拦截所有请求
                .anyRequest().authenticated();
    }
}

如果说没有请求放行则会返回如下

SpringSecurity

(2)、内置控制访问方法

瞅一瞅源码可得知

static final String permitAll = "permitAll";...............................................permitAll是允许所有
private static final String denyAll = "denyAll";...........................................denyAll是拒绝所有
private static final String anonymous = "anonymous";.......................................anonymous是允许匿名的
private static final String authenticated = "authenticated";...............................authenticated是需要认证
private static final String fullyAuthenticated = "fullyAuthenticated";.....................fullyAuthenticated是需要完整的认证
private static final String rememberMe = "rememberMe";.....................................rememberMe是记住,比如7天免登录这种

(3)、登录页

SpringBoot自带登录页开启 formLogin 后地址加端口即可访问,账号随意密码在项目启动时会在控制台打印

//使用Springboot自带的登录页
http.formLogin().and()
        //后面都是授权配置
        authorizeRequests()
        //匹配   证明   (拦截全部请求)
        .antMatchers("/**").authenticated();

SpringSecurity
SpringSecurity

(4)、使用自定义登录页

http.formLogin()
    //当发现login时认为是登录需要执行我们自定义的登录逻辑 >里面的url是登录页面表单的提交地址
    .loginProcessingUrl("/login")
    //登录成功后请求地址 请求方法必须是post的
    .successForwardUrl("/toMain")
    //设置登录页面
    .loginPage("/login.html")

    //放行登录页面
    .and
    .authorizeRequests()
    .antMatchers("/login").permitAll()

    //关闭csrf防护 >只有关闭了,才能接受来自表单的请求
     http.csrf().disable();

扯一嘴csrf攻击就是利用浏览器返回的Cookies和session

(5)、登出页

看源码注释会发现登出可以做很多操作,例如删除cookie

SpringSecurity
                    //登出后跳转页面
http.logout().logoutSuccessUrl("/");

附上api

表达式 说明 * hasRole([role]) 当前账户有指定角色时返回 true

, 默认情况下,角色都是以 ROLE_

开头,当然也可以在修改 DefaultWebSecurityExpressionHandler

中修改 defaultRolePrefix

自定义角色前缀 * hasAnyRole([role1,role2]) 当前账户有指定角色中的任意一个时返回 true

, 默认情况下,角色都是以 ROLE_

开头,当然也可以在修改 DefaultWebSecurityExpressionHandler

中修改 defaultRolePrefix

自定义角色前缀 hasAuthority([authority]) 当前账户有指定权限时返回 true

hasAnyAuthority([authority1,authority2]) 当前账户有指定权限中任何一个时返回 true

principal 允许当前用户直接访问的对象主体 authentication 允许直接访问从SecurityContext获得的当前身份验证对象 permitAll 允许所有 denyAll 拒绝所有 isAnonymous() 是否匿名用户 isRememberMe() 当前是否被记住 * isAuthenticated() 是否已经登录 isFullyAuthenticated() 是否已经登录 或 被记住 * hasPermission(Object target, Object permission) Returns true if the user has access to the provided target for the given permission. For example, hasPermission(domainObject, ‘read’) * hasPermission(Object targetId, String targetType, Object permission) Returns true if the user has access to the provided target for the given permission. For example, hasPermission(1, ‘com.example.domain.Message’, ‘read’) hasIpAddress([ip address]) IP地址是否是???

三、角色权限判断

利用@PreAuthorize注解自定义权限校验
开启@EnableGlobalMethodSecurity(prePostEnabled = true)注解, 在继承 WebSecurityConfigurerAdapter 这个类的类上面贴上这个注解.并且prePostEnabled设置为true,@PreAuthorize这个注解才能生效,SpringSecurity默认是关闭注解功能的.

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

(1)、UserDetailsService(基于数据库自定义UserDetailsService实现认证)

UserDetailsService接口用于返回用户相关数据。它有loadUserByUsername()方法,根据username查询用户实体,可以实现该接口覆盖该方法,实现自定义获取用户过程。该接口实现类被DaoAuthenticationProvider 类使用,用于认证过程中载入用户信息。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    private final String user = "admin";
    private final String pas = "$2a$10$kkPpRCSQJii1BdV77TqAbuWtBFAvtUGqFor.AbyGxGT.avFH/buU2";
    @Override
    //通过username去数据库查询账号密码
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List authorityList = new ArrayList<>();
        SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + "admin");
        authorityList.add(authority);
        SimpleGrantedAuthority authority1 = new SimpleGrantedAuthority("user:add");
        authorityList.add(authority1);
        return new User(user,pas,authorityList);
    }
}

//当然实际场景中账号密码和权限列表是通过数据库的查询获得的,最终返回一个User对象即可
//Security执行的权限检查不管你角色还是权限,他只比较字符

GrantedAuthority 有三个实现类,通常选用核心包中的 SimpleGrantedAuthority(单纯形权限)

SpringSecurity

(2)、配置Security

需要注意的是 WebSecurityConfigurerAdapter中有重载了三个configure

configure(AuthenticationManagerBuilder)认证管理器配置
用于通过允许轻松添加AuthenticationProviders来建立身份验证机制

configure(HttpSecurity)安全过滤器链配置
允许基于选择匹配在资源级别配置基于Web的安全性

configure(WebSecurity)核心过滤器配置
用于影响全局安全性的配置设置(忽略资源,设置调试模式,通过实现自定义防火墙定义拒绝请求),可设置UserDetails 和加密方式

通常使用过滤器链 configure(HttpSecurity)用来配置 HttpSecurity 。 HttpSecurity 用于构建一个安全过滤器链 SecurityFilterChain 。SecurityFilterChain 最终被注入核心过滤器

@Component
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    UserDetailsService userDetailsService;
    /**
     * 配置密码解析
     * @return
     */
    @Bean
    protected PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .formLogin().successForwardUrl("/index")
                .and()
                .authorizeRequests()
                .anyRequest()//所有请求
                .authenticated();//都需要身份认证
    }

}

(3)、请求鉴权(@PreAuthorize)

@PreAuthorize("hasAuthority('user:add')")
public String create(){
    return "添加功能:create";
}

需要给每个请求使用 @PreAuthorize(“hasAuthority(‘user:add’)”) 标识当然也可以用 @PreAuthorize(“hasAnyRole(‘ROLE_admin’)”)
注意:一定要以大写ROLE_开头后面随意(指定角色可以访问)

四、SpringSecurity提供支持表达式的注解

(1)、@PreAuthorize

可以用来控制一个方法是否能够被调用。也就是说先判断后执行

(2)、@PostAuthorize

先调用该接口,获得结果后在去判断该用户是否有权限(有意思的是如果接口有返回值用户没有权限最终不去返回结果罢了,但是操作还是做了)

(3)、@PreFilter

对集合类型的参数或返回值进行过滤,Spring Security将移除使对应表达式的结果为false的元素。

(4)、@PostFilter

注意@PostFilter注解只有在控制器方法的return返回值是一个集合的时候才可以使用;@PostFilter注解的作用:如果控制器方法的return返回值是一个集合,此注解可以对return的这个集合进行过滤输出;

(5)、@Secured注解

@Secured注解的作用:在用户向浏览器发送一个请求时会去访问控制器中的方法,然后在访问此控制器中的方法之前会先去UserDetailsService用户细节实现类的实现方法中return的User对象查看是否具有@Secured注解中指定的角色,如果有指定的角色,那么系统允许用户访问此控制器方法,否则,系统不允许访问此控制器方法;注意在使用@Secured设置角色名字的时候,角色名的前面一定要加上ROLE_前缀;

五、OAuth2

1、简介

很多网站、APP 弱化甚至没有搭建自己的账号体系,而是直接使用社会化登录的方式,这样不仅免去了用户注册账号的麻烦、还可以获取用户的好友关系来增强自身的社交功能。

比如我们可以使用微博登录简书,简书会自动将你的微博头像设置为你的简书头像,将你的微博昵称设置为你的简书昵称,甚至还可以获取你微博中的好友列表,提示你哪些朋友已经在使用简书,这是如何做到的呢?

最传统的办法是让用户直接在简书的登录页面输微博的账号和密码,简书通过用户的账号和密码去微博那里获取用户数据,但这样做有很多严重的缺点:

简书需要明文保存用户的微博账号和密码,这样很不安全。
简书拥有了获取用户在微博所有的权限,包括删除好友、给好友发私信、更改密码、注销账号等危险操作。
用户只有修改密码,才能收回赋予简书的权限。但是这样做会使得其他所有获得用户授权的第三方应用程序全部失效。
只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有使用微博登录的网站的数据泄漏。
为了解决以上的问题,OAuth 协议应运而生。

2、原理概要

新浪微博作为服务提供商,拥有用户的头像、昵称、邮箱、好友以及所有的微博内容,简书希望获取用户存储在微博的头像和昵称,假设它们是三个人:

1、简书问新浪微博:我想要获取用户 A 的头像和昵称,请你提供
2、微博说:我需要经过用户A 本人的许可,然后去问用户 A 是否要授权简书访问自己的头像和昵称
3、用户 A 对微博说:我给简书一个临时的钥匙,如果他给你出示了这把钥匙,你就把我的资料给他
4、简书使用户给它的钥匙获取用户头像和昵称信息。

也就是说这玩意就是搞第三方授权的咳咳。。。

SpringSecurity

3、流程图

SpringSecurity
SpringSecurity

4、授权模式

(1)、授权码模式

授权码模式是四种模式中最繁琐也是最安全的一种模式。
client向资源服务器请求资源,被重定向到授权服务器(AuthorizationServer)
浏览器向资源拥有者索要授权,之后将用户授权发送给授权服务器
授权服务器将授权码(AuthorizationCode)转经浏览器发送给client
client拿着授权码向授权服务器索要访问令牌
授权服务器返回Access Token和Refresh Token给cilent

这种模式是四种模式中最安全的一种模式。一般用于client是Web服务器端应用或第三方的原生App调用资源服务的时候。因为在这种模式中AccessToken不会经过浏览器或移动端的App,而是直接从服务端去交换,这样就最大限度的减小了AccessToken泄漏的风险。

SpringSecurity

(2)、简化模式/隐式授权模式

简化模式相对于授权码模式省略了,提供授权码,然后通过服务端发送授权码换取AccessToken的过程。
client请求资源被浏览器转发至授权服务器
浏览器向资源拥有者索要授权,之后将用户授权发送给授权服务器
授权服务器将AccessToken以Hash的形式存放在重定向uri的fargment中发送给浏览器
浏览器访问重定向URI
资源服务器返回一个脚本,用以解析Hash中的AccessToken
浏览器将Access Token解析出来
将解析出的Access Token发送给client

一般简化模式用于没有服务器端的第三方单页面应用,因为没有服务器端就无法使用授权码模式。

SpringSecurity

(3)、密码模式

用户将认证密码发送给client
client拿着用户的密码向授权服务器请求Access Token
授权服务器将Access Token和Refresh Token发送给client

这种模式十分简单,但是却意味着直接将用户敏感信息泄漏给了client,因此这就说明这种模式只能用于client是我们自己开发的情况下。因此密码模式一般用于我们自己开发的,第一方原生App或第一方单页面应用。

SpringSecurity

(4)、客户端模式

这是一种最简单的模式,只要client请求,我们就将AccessToken发送给它。
client向授权服务器发送自己的身份信息,并请求AccessToken
确认client信息无误后,将AccessToken发送给client

这种模式是最方便但最不安全的模式。因此这就要求我们对client完全的信任,而client本身也是安全的。因此这种模式一般用来提供给我们完全信任的服务器端服务。在这个过程中不需要用户的参与。

SpringSecurity

(5)、四种模式的应用场景

1、授权码模式:第三方Web服务器端应用与第三方原生App

2、简化模式:第三方单页面应用

3、密码模式:第一方单页应用与第一方原生App

4、客户端模式:没有用户参与的,完全信任的服务器端服务

Original: https://www.cnblogs.com/pkkyh/p/14631415.html
Author: 迷途者寻影而行
Title: SpringSecurity

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/575760/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 如何成为一名开发人员——第 1 部分:编码技巧

    1 学习一门语言 程序员编写计算机代码,所以你必须学会说这种语言。 但是, 你首先学习哪种编程语言并不重要!这完全取决于你对什么感兴趣。例如… 如果你想进入 Web 开…

    数据库 2023年6月14日
    0100
  • Java redisTemplate 使用 increment序列化问题

    添加key: ValueOperations redisTemplate.setValueSerializer(new StringRedisSerializer()); // 设…

    数据库 2023年6月9日
    0109
  • day41-网络编程03

    Java网络编程03 5.UDP网络通信编程[了解] 5.1基本介绍 类 DatagramSocket和 DatagramPacket[&#x6570;&#x636…

    数据库 2023年6月11日
    0100
  • 线程池系列一:线程池原来是个外包公司,打工人我悟了

    我们在工作中经常用到线程池,线程池(Thread Pool)是一种基于池化思想管理线程的工具。 线程的作用是处理任务,而池则是帮助我们实现资源的重复利用和管理。线程池就是帮助我们异…

    数据库 2023年6月6日
    094
  • MySQL之文件

    1.参数文件 当MySQL实例启动时,数据库会先去读一个配置参数文件,用来寻找数据库的各种文件所在的位置以及指定某些初始化参数,这些参数通常定义了某种内存结构有多大等。在默认轻快下…

    数据库 2023年6月6日
    071
  • IDEA中Git的使用

    Git在IDEA中的使用 JAVA技术交流群:737698533 创建和导入 创建一个新项目到Gitee上 首先创建一个仓库,勾选上初始化 获取新创建仓库的路径 然后随便在一个文件…

    数据库 2023年6月16日
    079
  • 0. 数据库设计规范化

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    数据库 2023年6月16日
    0100
  • Mybatis-Plus 实现乐观锁

    是指在读取一行数据时,记下它的版本号、最近修改的时间戳或校验和。然后,你可以在修改记录之前检查版本有没有发生变化。 适用场景 适用于读多写少的场景,乐观锁相信事务之间的数据竞争概率…

    数据库 2023年6月6日
    091
  • MySQL启动过程详解三:Innodb存储引擎的启动

    Innodb启动过程如下: 初始化innobase_hton,它是一个handlerton类型的指针,以便在server层能够调用存储引擎的接口。 Innodb相关参数的检车和初始…

    数据库 2023年6月9日
    094
  • jdbc-使用java连接mysql

    package com.cqust; import com.mysql.jdbc.Driver; import java.sql.Connection;import java.sq…

    数据库 2023年5月24日
    061
  • redis启动服务闪退,端口被占用

    1、首先查询一下redis端口的pid,使用命令【netstat -ano | findstr 端口号】redis默认端口号是6379 (注意!如果netstat命令使用不了的话,…

    数据库 2023年6月11日
    0116
  • Python学习笔记2(未完待续)

    Python学习笔记2(未完待续) 解决plt中文乱码问题-方法1 plt.rcParams[“font.sans-serif”]=[“SimH…

    数据库 2023年6月14日
    074
  • 链表问题一些常用的套路与方法

    概述 链表问题应该是数据结构中比较基础的一类问题,但同时也是在面试中常考的一类问题。但是围绕链表问题的一些基本方法或者处理思想,也无外乎那几类,因此本文尝试对链表常用的一些方法或者…

    数据库 2023年6月11日
    079
  • 上传jar包到私有仓库nexus3

    上传Jar包到私有仓库Nexus3 官方文档 上传组件(Jar包) POST /service/rest/v1/components 官方例子: curl -v -u admin:…

    数据库 2023年6月9日
    084
  • JavaScript Date 时间类型 .toISOString() 时差问题

    JS中使用 toISOString 方法导致差了8个小时的问题 使用 getTimezoneOffset() 返回本地时间与格林威治标准时间 (GMT) 的分钟差。对差的时间进行补…

    数据库 2023年6月11日
    089
  • Linux 下重启 PHP 服务、nginx 服务

    一、重启 PHP 服务 service php-fpm start 开启 service php-fpm stop 停止 service php-fpm restart 重启 二、…

    数据库 2023年6月14日
    069
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球