Security 详解—原理(1)

news2024/11/17 13:52:16

1.简介:

        Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spring 家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。

1.1 特性:

  • 支持对身份认证和访问鉴权的自定义扩展
  • 防止会话固定、点击劫持、跨站点请求伪造等攻击
  • Servlet API 集成
  • 与 Spring Web MVC 的可选集

Spring Security的核心是提供认证(Authentication)、授权(Authorization)和攻击防护。

1.2 认证(Authentication)

        身份认证,指验证用户是否为使用系统的合法主体,就是说用户能否访问该系统。 

        Spring Security支持的认证方式有:用户名和密码、OAuth2.0登录、SAML2.0登录、中央认证服务器(CAS)、记住我、JAAS身份认证、OpenID、预身份验证方案、X509认证

1.3 授权(Authorization)

        身份鉴权,指验证某个用户是否具有权限使用系统的某个操作。

Spring Security支持的授权方案:基于过滤器授权、基于表达式访问控制、安全对象实现、方法安全、域对象安全(ACL)。

1.4 攻击防护

        防止会话固定、点击劫持、跨站点请求伪造等攻击。(解决系统安全问题)

Spring Security支持的攻击防护有:CSRF、会话固定保护、安全请求头、HTTPS、HTTP防火墙

2 SpringSecurity 认证和授权流程

        Spring Security是通过Filter来实现的,采用的是责任链的设计模式,它有一条很长的过滤器链,只有当前过滤器通过,才能进入下一个过滤器。

        Spring Boot 自动装配通过WebSecurityConfiguration类,Spring容器中注入一个名为SpringSecurityFilterChain的Servlet过滤器,类型为FilterChainProxy。它实现了javax.servlet.Filter,因此外部的请求都会经过这个类。FilterChainProxy是一个代理,真正起作用的是FilterChainProxy中SecurityFilterChain所包含的各个Filter,同时,这些Filter都已经注入到Spring容器中,他们是Spring Security的核心,各有各的职责。但是他们并不直接处理用户的认证和授权,而是把他们交给了认证管理器(AuthenticationManager)和决策管理器(AccessDecisionManager)进行处理

 FilterChainProxy类图:

过滤器图: 

 

         除了默认过滤器,我们也可以自定义多个过滤器,通过configure(HttpSecurity http)方法中配置。认证的过程围绕图中过滤链的橙色部分(过滤器Filter),动态鉴权主要是围绕其绿色部分(拦截器Interceptor)。

 内置的过滤器:

序号名称描述
1WebAsyncManagerIntegrationFilter根据请求封装获取WebAsyncManager,从WebAsyncManager获取/注册的安全上下文可调 用处理拦截器
2SecurityContextPersistenceFilterSecurityContextPersistenceFilter主要是使用SecurityContextRepository在session中保存 或更新一个SecurityContext,并将SecurityContext给以后的过滤器使用,来为后续fifilter 建立所需的上下文。SecurityContext中存储了当前用户的认证以及权限信息。
3HeaderWriterFilter向请求的Header中添加相应的信息,可在http标签内部使用security:headers来控制
4CsrfFiltercsrf又称跨域请求伪造,SpringSecurity会对所有post请求验证是否包含系统生成的csrf的 token信息,如果不包含,则报错。起到防止csrf攻击的效果。
5LogoutFilter匹配URL为/logout的请求,实现用户退出,清除认证信息。
6UsernamePasswordAuthenticationFilter认证过滤器,表单认证操作全靠这个过滤器,默认匹配URL为/login且必须为POST请求
7DefaultLoginPageGeneratingFilter如果没有在配置文件中指定认证页面,则由该过滤器生成一个默认认证页面。
8DefaultLogoutPageGeneratingFilter由此过滤器可以生产一个默认的退出登录页面
9BasicAuthenticationFilter此过滤器会自动解析HTTP请求中头部名字为Authentication,且以Basic开头的头信息
10RequestCacheAwareFilter通过HttpSessionRequestCache内部维护了一个RequestCache,用于缓存 HttpServletRequest
11SecurityContextHolderAwareRequestFilter针对ServletRequest进行了一次包装,使得request具有更加丰富的API
12AnonymousAuthenticationFilter当SecurityContextHolder中认证信息为空,则会创建一个匿名用户存入到 SecurityContextHolder中。spring security为了兼容未登录的访问,也走了一套认证流程, 只不过是一个匿名的身份。
13SessionManagementFiltersecurityContextRepository限制同一用户开启多个会话的数量
14ExceptionTranslationFilter异常转换过滤器位于整个springSecurityFilterChain的后方,用来转换整个链路中出现的异 常
15FilterSecurityInterceptor授权过滤器,获取所配置资源访问的授权信息,根据SecurityContextHolder中存储的用户信息来决定其 是否有权限。


2.1 认证流程

Spring Security有两种认证方式,一种是 HttpBasic认证和表单认证。

  • HttpBasic登录验证模式是Spring Security实现登录验证最简单的一种方式,也可以说是最简陋 的一种方式。它的目的并不是保障登录验证的绝对安全,而是提供一种“防君子不防小人”的登录验证。
  • 表单认证就是通过登录界面,将用户名密码通过表单的形式发送到服务器上。
  •  spring security 5.x以下默认是HttpBasic认证,以上默认是表单认证。

 具体流程:

  1. 用户提交用户名、密码被SecurityFilterChain中的UsernamePasswordAuthenticationFilter 过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
  2. 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证,它的实现类是ProviderManager。
  3. 认证成功后, AuthenticationManager 身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication 实例。
  4. SecurityContextHolder 安全上下文容器将第3步填充了信息的 Authentication,通过 SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。

ProviderManager
AbstractAuthenticationProcessingFilter

UsernamePasswordAuthenticationFilter
ProviderManager

                          

2.1.1  HttpBasic认证

    @Override
    public void configure(HttpSecurity http) throws Exception {
        
        http.csrf().disable();

        http.authorizeRequests()
                .antMatchers("/hello", "/loginalert", "/mylogin").permitAll()
                .antMatchers("/helloadmin").hasRole("admin")
                .antMatchers("/hellouser").hasAuthority("query")
                .anyRequest().authenticated()
                .and().httpBasic();
    }

2.1.2 表单认证

 @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();

        http.authorizeRequests()
                .antMatchers("/hello", "/loginalert", "/mylogin").permitAll()
                .antMatchers("/helloadmin").hasRole("admin")
                .antMatchers("/hellouser").hasAuthority("query")
                .anyRequest().authenticated()
                .and().formLogin().loginPage("/mylogin.html")
                .usernameParameter("uname").passwordParameter("passwd")
                .permitAll()
                .loginProcessingUrl("/doLogin")
                .failureHandler((request, response, exception) -> {
                    String message = "login fail:" + exception.getMessage();
                    response.setContentType("text/html");
                    response.getWriter().write("<script>alert('" + message + "');window.location.href='/mylogin.html'</script>");
                }).successHandler(((request, response, authentication) -> {
                    String message = "login success:" + authentication.getName();
                    response.setContentType("text/html");
                    response.getWriter().write("<script>alert('" + message + "');window.location.href='/index'</script>");
                }));

        http.exceptionHandling().accessDeniedHandler(((request, response, accessDeniedException) -> {
            String message = "access fail:" + accessDeniedException.getMessage();
            response.setContentType("text/html");
            response.getWriter().write("<script>alert('" + message + "');window.location.href='/index'</script>");

        }));

    }

 2.2 授权流程

        授权是在用户认证通过后,对访问资源的权限进行检查的过程。Spring Security可以通过http.authorizeRequests()对web请求进行授权保护。Spring Security使用标准Filter建立了对web请求的拦截,最终实现对资源的授权访问。

  1. 拦截请求,已认证用户访问受保护的web资源将被SecurityFilterChain中(实现类为DefaultSecurityFilterChain)的 FilterSecurityInterceptor 的子类拦截。
  2. 获取资源访问策略,FilterSecurityInterceptor会从 SecurityMetadataSource的子类DefaultFilterInvocationSecurityMetadataSource 获取要访问当前资源所需要的权限Collection 。SecurityMetadataSource其实就是读取访问策略的抽象,而读取的内容,其实就是我们配置的访问规则,读取访问策略如
  3. 最后,FilterSecurityInterceptor会调用 AccessDecisionManager 进行授权决策,若决策通过,则允许访问资源,否则将禁止访问。 

                 

2.2.1 权限配置 

        权限配置有两种方式一种在SecurityFilterChain中配置,另一种在接口上增加注解。

        权限表达式(方法):

  1. hasRole(role):当前用户是否具备指定角色
  2. hasAnyRole(role …):当前用户是否具备指定角色中的任意一个
  3. hasAuthority(authority):当前用户是否具备指定的权限
  4. hasAnyAuthority(authority …):当前用户是否具备指定的权限任意一个
  5. principal:当前登录主体
  6. authentication:context中authentication对象
  7. permitAll():允许所有请求
  8. denyAll():拒绝所有请求
  9. isAnonymous():当前用户是否是一个匿名用户

        1. SecurityFilterChain配置

.antMatchers("/toUserAdd").hasAnyRole("admin");
.antMatchers("/toUserAdd").hasRole("admin");
.antMatchers("/toUserEdit").hasAuthority("edit")
.antMatchers("/toUserEdit").hasAnyAuthority("edit")

        2.注解方式

  1. @PostAuthorize:在目标方法执行之后进行权限校验
  2. @PostFilter:在目标方法执行之后对方法的返回结果进行过滤
  3. @PreAuthorize:在目标方法执行之前进行权限校验。
  4. @PreFilter:在目标方法执行之前对方法参数进行过滤。
  5. @Secured:访问目标方法必须具备相应的角色
  6. @DenyAll:拒绝所有访问
  7. @PermitAll: 允许所有访问
  8. @RolesAlowed:访问目标方法必须具有的角色
public class UserService {
    @PreAuthorize("hasRole('ADMIN')")
    public String hello() {
        return "hello";
    }
    @PreAuthorize("hasRole('ADMIN') and authentication.name=='lglbc'")
    public String hello2() {
        return "hello";
    }
    @PreAuthorize("hasRole('ADMIN') and authentication.name==#name")
    public String hello3(String name) {
        return "hello";
    }

    @PreFilter(value = "filterObject.id%2!=0",filterTarget = "users")
    public void addUsers(List<User> users, Integer other) {
        System.out.println("users = " + JSON.toJSONString(users));
    }
    @PostFilter("filterObject.id%2==0")
    public List<User> getAll() {
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            users.add(new User(i, "lglbc_:" + i));
        }
        return users;
    }

    @Secured({"ROLE_ADMIN","ROLE_USER"})
    public User getUserByUsername(String username) {
        return new User(99, username);
    }

    @DenyAll
    public String denyAll() {
        return "DenyAll";
    }

    @PermitAll
    public String permitAll() {
        return "PermitAll";
    }
    @RolesAllowed({"ADMIN","USER"})
    public String rolesAllowed() {
        return "RolesAllowed";
    }
}

2.2.2  hasRole 和hasAuthority  区别

        通过原来分析,hasRole 的处理逻辑和 hasAuthority 似乎是一样的,只是hasRole 这里会自动给传入的字符串前缀(默认是ROLE_ ),使用 hasAuthority 更具有一致性,不用考虑要不要加 ROLE_ 前缀,在UserDetailsService类的loadUserByUsername中查询权限,也不需要手动增加。在SecurityExpressionRoot 类中hasAuthority 和 hasRole 最终都是调用了 hasAnyAuthorityName 方法。

3.异常处理

        异常处理设计到两个 Handler 进行处理 ,一个是处理认证异常的Handler处理器 AuthenticationEntryPoint,一个是授权异常的Handler处理器 AccessDeniedHandler。异常类主要分为两大类:AuthenticationException认证异常和AccessDeniedException授权异常。

AuthenticationException异常:

异常类型备注
AuthenticationException认证异常的父类,抽象类
BadCredentialsException登录凭证(密码)异常
InsufficientAuthenticationException登录凭证不够充分而抛出的异常
SessionAuthenticationException会话并发管理时抛出的异常,例如会话总数超出最大限制数
UsernameNotFoundException用户名不存在异常
PreAuthenticatedCredentialsNotFoundException身份预认证失败异常
ProviderNotFoundException未配置AuthenticationProvider 异常
AuthenticationServiceException由于系统问题而无法处理认证请求异常。
InternalAuthenticationServiceException由于系统问题而无法处理认证请求异常。和AuthenticationServiceException 不同之处在于,如果外部系统出错,则不会抛出该异常
AuthenticationCredentialsNotFoundExceptionSecurityContext中不存在认证主体时抛出的异常
NonceExpiredExceptionHTTP摘要认证时随机数过期异常
RememberMeAuthenticationExceptionRememberMe认证异常
CookieTheftExceptionRememberMe认证时Cookie 被盗窃异常
InvalidCookieExceptionRememberMe认证时无效的Cookie异常
AccountStatusException账户状态异常
LockedException账户被锁定异常
DisabledException账户被禁用异常
CredentialsExpiredException登录凭证(密码)过期异常
AccountExpiredException账户过期异常

AccessDeniedException异常:

异常类型备注
AccessDeniedException权限异常的父类
AuthorizationServiceException由于系统问题而无法处理权限时抛出异常
CsrfExceptionCsrf令牌异常
MissingCsrfTokenExceptionCsrf令牌缺失异常
InvalidCsrfTokenExceptionCsrf令牌无效异常

可以通过SecurityFilterChain进行配置

        http.exceptionHandling().accessDeniedHandler(((request, response, accessDeniedException) -> {
            String message = "access fail:" + accessDeniedException.getMessage();
            response.setContentType("text/html");
            response.getWriter().write("<script>alert('" + message + "');window.location.href='/index'</script>");
        }));

        http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
            System.out.println("error:" + authException);
        });

参考:

SpringBoot Security工作原理_springbootsecurity原理_StrangerIt的博客-CSDN博客

springSecurity源码之鉴权原理_凯歌的博客的博客-CSDN博客

SpringSecurity认证基本原理与认证2种方式_spring security 多种认证_程序小黑马的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/660290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不可盲目优化,否则不是缘木求鱼就是南辕北辙

作为在编码这块自留地里深耕多年的码农&#xff0c;凭借着自认为丰富的经验加上专业领域的博览群书&#xff0c;自觉对程序优化还是有点感觉、有点心得的。但最近的经历让我不得不感慨&#xff0c;“不听老人言&#xff0c;吃亏在眼前“还是很有道理的。 软件优化这件事&#x…

VS code安装与配置

1.VS code介绍 2.VS code安装 2.1解压&#xff0c;并打开解压之后的文件夹&#xff0c;点击VSCodeUserSetup-x64-1.67.0&#xff0c;右击&#xff0c;选择以管理员身份运行 2.2点击同意&#xff0c;点击下一步 2.3更换安装路径 2.4点击下一步 2.5勾选创建桌面快捷方式&…

如何在 Linux 中列出 Systemd 下所有正在运行的服务

动动发财的小手&#xff0c;点个赞吧&#xff01; Linux系统提供多种系统服务&#xff08;如进程管理、登录、syslog、cron等&#xff09;和网络服务&#xff08;如远程登录、电子邮件、打印机、虚拟主机、数据存储、文件传输、域名解析等&#xff09; &#xff08;使用 DNS&am…

腾讯云服务器地域有什么区别怎么选比较好?

腾讯云服务器地域什么区别&#xff1f;云服务器地域怎么选择&#xff1f;地域是指云服务器所在机房的地理位置&#xff0c;用户距离地域越近网络延迟越低&#xff0c;速度越快&#xff0c;所以地域就近选择即可。广州上海北京等地域网站域名需要备案&#xff0c;中国香港或其他…

C# hello world

目录 一 C#简介 二 Hello world程序 三 C#未来的发展趋势 四 C#学习路线推荐 一 C#简介 C#&#xff08;C Sharp&#xff09;是微软开发的一种面向对象的编程语言&#xff0c;它于2000年发布&#xff0c;并被设计为在.NET平台上运行。C#语言具有简单、安全、类型安全、可扩…

飞只因太美,给你的首页装上吧!

原文链接&#xff1a;飞只因太美&#xff0c;给你的首页装上吧&#xff01; 推荐阅读 基于 Hexo 从零开始搭建个人博客&#xff08;一&#xff09;基于 Hexo 从零开始搭建个人博客&#xff08;二&#xff09;基于 Hexo 从零开始搭建个人博客&#xff08;三&#xff09;基于 H…

你要一定用的上的Postman 使用小技巧

目录 一、什么是 Postman&#xff08;前世今生&#xff09; 二、使用变量 2.1 变量作用域适用于 Postman 中不同的场景 2.2 编辑全局和环境变量 2.3 编辑集合变量 2.4 使用系统内置动态变量 三、Postman 请求生命周期 3.1 在前置请求&#xff08;pre-request script&…

【期末总复习】神经网络与深度学习蒲公英书

浅层学习 one-hot向量 相似度的概念 局部表示和分布式表示示例 学习器 准确率 机器学习的三个基本要素&#xff1a;模型、学习准则、优化算法 【概念】期望风险 【概念】损失函数 【运用】三分类问题 【概念】过拟合 【概念】欠拟合 超参数 【选择 / 判断】验证集概念 线性回归…

C语言实现链表

绪论 机遇对于有准备的头脑有特别的亲和力。本章将讲写到链表其中主要将写到单链表和带头双向循环链表的如何实现。 话不多说安全带系好&#xff0c;发车啦&#xff08;建议电脑观看&#xff09;。 附&#xff1a;红色&#xff0c;部分为重点部分&#xff1b;蓝颜色为需要记忆的…

oracle expdp导致system表空间满

今天下午&#xff0c;项目经理反馈有套11204版本数据库无法使用了&#xff0c;立刻登录检查环境发现SYSTEM表空间使用率99.99%了 TABLESPACE_NAME MAXSIZE_MB ACTUALSIZE_MB USED_MB FREESPACE_MB SPACE USAGE ----------------- ---------- ------------- ---------- …

单向散列函数(哈希)【密码学】(一)

目录 一、前言&#xff1a;密码学有什么用&#xff1f; 二、单向散列函数 1、单向函数 2、散列函数 3、单向散列函数 三、怎么解决完整性问题 四、如何设置合适的安全强度 一、前言&#xff1a;密码学有什么用&#xff1f; 二、单向散列函数 单向散列函数就是用来解决…

哈工大计算机网络传输层协议详解之:可靠数据传输的基本原理

哈工大计算机网络传输层协议详解之&#xff1a;可靠数据传输的基本原理 可靠数据传输原理 什么是可靠&#xff1f; 不错、不丢、不乱 可靠数据传输协议 可靠数据传输对应用层、传输层、链路层都很重要 网络Top-10问题 信道的不可靠特性决定了可靠数据传输协议(rdt)的复杂性…

【最全】如何不写代码将 Dicom 图像转 Nifti 格式, 7种工具任你选!

大多数医学成像设备以复杂的 DICOM 格式(后缀 .dcm)的变体存储图像。许多科学工具希望医学图像以更简单的 NIfTI 格式&#xff08;后缀 nii.gz&#xff09;存储。事实上&#xff0c;我们做深度学习基本都是使用的 nii.gz 格式或者 nii 格式。 那么&#xff0c;如何将 dicom 格…

一文吃透 CSS Flex 布局

原文链接&#xff1a;一文吃透 CSS Flex 布局 教学游戏 这里有两个小游戏&#xff0c;可用来练习 flex 布局。 塔防游戏 送小青蛙回家 Flexbox 概述 Flexbox 布局也叫 Flex 布局&#xff0c;弹性盒子布局。 它决定了元素如何在页面上排列&#xff0c;使它们能在不同的屏幕…

Mysql索引、事务以及存储引擎

目录 一、索引 1.概述 2.作用 3.索引的缺点 4.创建索引的原则依据 5.索引分类和创建 5.1普通索引 5.2唯一索引 5.3主键索引 5.4组合索引&#xff08;单列索引与多列索引&#xff09; 5.5全文索引&#xff08;FULLTEXT&#xff09; 6.查看索引 7.删除索引 二、事务…

测试必会技能之接口性能测试方案你会不会写?

目录 一、 性能测试术语解释 二、 性能测试方法及目标 三、 性能需求分析 四、 性能测试范围 五、 并发数计算方法 六、 性能测试用例与场景 七、 性能测试工具选择 八、 性能测试结果分析 九、 性能测试通过标准 总结&#xff1a; 一、 性能测试术语解释 …

腾讯云服务器可用区什么意思?

腾讯云服务器可用区什么意思&#xff1f;可用区&#xff08;Zone&#xff09;是指腾讯云在同一地域内电力和网络互相独立的物理数据中心&#xff0c;一个可用区故障不会影响另一个可用区的正常运行&#xff0c;所以可用区用于构建高容灾、高可靠性应用。腾讯云服务器网来详细说…

java为什么不支持多继承

Java为什么不支持多继承 前面我们提到过“继承则好比武侠中的传承血脉&#xff0c;子类可以继承父类的属性和方法&#xff0c;并且可以根据需要进行自我扩展&#xff0c;这样就不用从头造轮子&#xff0c;提高了代码的重用性和可维护性。”&#xff0c;在java中支持接口实现多继…

龙芯电脑(LoongArch)如何升级BIOS(UEFI固件)

龙芯UEFI 获取地址&#xff08;包括3A5000 台式机&#xff0c;笔记本&#xff0c;3C5000 服务器&#xff09;&#xff1a; gitee: https://gitee.com/loongson/Firmware github: https://github.com/loongson/Firmware 根据自身机型选择相应的固件&#xff08;Image目录有相…

第七章——微分方程

注&#xff1a;//之后的都是注释&#xff0c;不是过程。 一、求常系数线性齐次微分方程的通解 1.一般形式&#xff1a;ypyqy0。 2.齐次&#xff1a;“齐次”的含义就是次数相等&#xff0c;ypyqy0都是一次幂&#xff0c;所以是齐次线性微分方程&#xff0c;如果说加上一个常…