SpringBoot下使用Security

该文基于SpringBoot版本2.1.8.RELEASE,测试代码仓库地址:https://github.com/uetty/spring-boot-clean/tree/security,主要在security命名的分支之下,可以点到release查看代码案例列表,或拉取整个仓库代码在IDE中直观地查看所有分支提交历史。

这篇文章能帮助你什么?如果你有如下疑问,可以尝试阅读本文,希望读完这篇文章能够对你有所帮助。

  1. Security如何进行登录,登录模块是否需要在Controller中完成?
  2. Security能否适应各种各样自定义的登录功能?
  3. Security是如何进行权限验证的?
  4. Security能否适应各种各样的权限验证的逻辑?
  5. 什么是CSRF攻击,Security是否支持CSRF攻击的防范?
  6. 如何利用Security自带的Oauth封装,快速搭建常见网站的(常规风格的)Oauth客户端支持?

(一)Spring Security框架结构

在网络安全领域,访问控制主要包括身份识别(即主体宣称身份)、身份认证、权限授予、监控与记录、问责这几块内容。无论是Spring Security还是Shiro或者其他权限框架,至少都包含了身份识别、身份认证、权限授予三块。从大的角度来看,权限框架主要包含认证和授权两大模块,Spring Security代码上对认证模型和授权模型的实现大致如下。

(Ⅰ)认证模型

在这里插入图片描述

(Ⅱ)授权模型

授权模型根据代码配置的不同,存在两条可能的路径,doFilter方法在Filter拦截器层实现授权,DispatchServlet.service方法在进入control前实现授权,两条路径的授权,最终都归于决策管理器与投票器逻辑。

在这里插入图片描述

(二)配置文件简单示例

继承WebSecurityConfigureAdapter类,加上@EnableWebSecurity注解,并实现configure方法(注意这个方法有三种入参形式,下面只是其中一种,后面的篇幅中会看到另外一种),下面只是一个简单的配置文件,仅配置了一些简单的URL路径相关的权限。

SecurityConfigure.class

@EnableWebSecurity
public class SecurityConfigure extends WebSecurityConfigurerAdapter {
   
    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        http.authorizeRequests()
                // 允许这些路径不用验证
                .antMatchers("/test", "/static").permitAll()
                // 这些路径需要USER角色的权限
                .antMatchers("/user/**").hasRole("USER")
                // 其余的路径都需要登录
                .anyRequest().authenticated();
                // 实际还会有其他设置,这里不列出
    }
}

(三)登录功能

spring security已经帮你完成了登录验证的代码,无需再在controller中进行编码。

该部分前两个案例意义不大,建议可以直接跳(Ⅲ)案例。

(Ⅰ)最简陋且无意义的登录配置案例

该案例与上面一样,配置在实现WebSecurityConfigureAdapter接口的类中,如下所示:

SecurityConfigure.class

@EnableWebSecurity
public class SecurityConfigure extends WebSecurityConfigurerAdapter {
   
    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        // 这里为了测试方便暂时先禁用csrf
        http.csrf().disable();
        http
            .authorizeRequests()
            // 拥有其中一项权限即可,"USER"权限与UserDetails的Authorities中"USER"匹配
            // .antMatchers("/api/user/**").hasAnyAuthority("USER", "ADMIN")
            // 其余的路径都需要登录
            .anyRequest().authenticated();
            // 上面是权限相关的配置,后面第五部分详细介绍
            
            .and()
            .formLogin()
            // 登录页面地址(也即判断请求未登录验证时,重定向到的页面)
            .loginPage("/login")
            // 登录接口路径
            .loginProcessingUrl("/api/login")
            // 登录成功后重定向到的页面地址
            .defaultSuccessUrl("/index")
            // 登录失败时重定向到的页面
            .failureUrl("/login-error")
            // 登录接口传递用户名的参数名
            .usernameParameter("username")
            // 登录接口传递密码的参数名
            .passwordParameter("password")
            ;
    }
}

在这种配置下,既没有指定自定义登录验证逻辑,又没有指定用户名密码,spring security会自动生成密码,会在启动时在控制台打印如下所示(可以看到是INFO级别log,看不到的话除了可能是配置问题还要考虑日志级别问题)

2020-04-15 01:14:18,430 [main] o.s.b.a.s.s.UserDetailsServiceAutoConfiguration.getOrDeducePassword:83 [INFO] - 

Using generated security password: f31ad0b3-5247-4a2a-864c-b6a3e4a0b936

前端代码是从spring官网拿的文件,是前后端不分离的thymeleaf文件(前端案例之所以是不分离,是因为security还提供了CSRF功能,这个会通过前后端不分离的thymeleaf页面自动将token写入到页面,CSRF后面会说,涉及到安全的,这里不用关心),具体前端代码这里就不贴了。

登录测试,登录接口(不是登录页面)是POST请求,在POST MAN中大概就是这样

http://localhost:9090/api/login
form表单参数如下
username: user
password: f31ad0b3-5247-4a2a-864c-b6a3e4a0b936

登录成功,返回的是index页面的内容。

这个案例并不实用,仅有的一点意义是展示一下security登录成功后重定向地址的配置以及登录接口参数名的配置。

案例地址:https://github.com/Uetty/spring-boot-clean/tree/security-login-1.0

代码版本:https://github.com/Uetty/spring-boot-clean/releases/tag/security-login-1.0

(Ⅱ)增加一点配置的仍旧无意义登录配置案例

在这个案例中,将自动生成的密码改成了代码中写死的密码。配置如下:

SecurityConfigure.class

@EnableWebSecurity
public class SecurityConfigure extends WebSecurityConfigurerAdapter {
   
    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        // 这里跟第(Ⅰ)个案例的配置一样,略了,从上面拷下来就行
        ...
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   
        // 注意这里跟上面方法名相同,参数不同,不要混了
        // 这个会将密码加密后再存在内存中
        UserDetails build = User.withDefaultPasswordEncoder()
                .username("vince")
                .password("123456")
                .roles("USER")
                .build();
        auth.inMemoryAuthentication()
        .withUser("vince").roles("USER").password(build.getPassword());
    }
}

登录测试还是跟上面一个案例一样,不再赘述。

这个案例同样意义不大,仅有的意义大概就是展示了一下Spring内存对密码是有加密的特性,自己可以debug查看一下,确实是加密了的

案例地址:https://github.com/Uetty/spring-boot-clean/tree/security-login-1.1

(Ⅲ)自定义登录验证

如前面Security架构图所示,Security使用了Servlet规范的过滤器(Filter)与过滤链(FilterChain)来组织自身的结构,整个Security框架主要功能由多个过滤器堆叠串联而成,每个过滤器负责了一个特定的功能。如Session层过滤器、请求头处理过滤器、登出逻辑处理过滤器、缓存处理层过滤器等,一般会有至少十一个过滤器存在。登录处理层也是其中的一个过滤器,一般置于登出处理过滤器之后,位于第5位。

在登录层,较常使用的是UsernamePasswordAuthenticationFilter过滤器,即基于用户名密码的过滤器。为了能够满足多种多样的需求,Security在UsernamePasswordAuthenticationFilter过滤器内部的不同层次均暴露了接口,框架使用者能够根据需要自定义实现任意某一层的接口,下面基于它介绍各层接口:

  1. UsernamePasswordAuthenticationFilterUsernamePasswordAuthenticationFilter类大部分代码都是继承于它的父级抽象类AbstractAuthenticationProcessingFilterUsernamePasswordAuthenticationFilter自身的代码最主要的作用在于定义了Authentication实例的类型,该类型决定了该登录过滤器能被哪些AuthenticationProvider(下面介绍)处理。而父级抽象类AbstractAuthenticationProcessingFilter,则是登录逻辑的实际执行者,这样设计的好处在于,父级抽象类定义的逻辑的代码可以被多个登录过滤器复用。

    由于后面已经有添加自定义Filter的章节,所以通过自定义Filter的方式重写登录认证的案例这里不再提供,参考后面章节即可。

    自定义登录Filter要注意的是:

    ​ 1) 需要验证请求路径是否为登录接口;

    ​ 2) 是否有其他Session存储的业务逻辑需求;

    ​ 3) Spring自身有事件通知机制,登录成功也是一种事件,如有事件监听的需要,实现ApplicationEventPublisherAware接口,即可获取ApplicationEventPublisher实例,事件推送代码参考AbstractAuthenticationProcessingFilter.successfulAuthentication代码;

    ​ 4) 登录成功后,需要调用SecurityContextHolder.getContext().setAuthentication( authentication )设置认证信息。

  2. AuthenticationManager:见前面结构图。AbstractAuthenticationProcessingFilter中的登录逻辑主要委托给了AuthenticationManager认证管理器接口,默认的认证管理器接口的实现类是ProviderManager认证提供者管理器类ProviderManager允许有父级AuthenticationManager存在,本机ProviderManager不能处理的时候,才会交给父级ProviderMananger尝试处理。默认情况下,第一级ProviderMananger是负责处理AnonymousAuthenticationTokenProviderManager,而UsernamePasswordAuthenticationToken是由其父级ProviderMananger处理。由于AuthenticationManager本身并没有什么功能,所以比较少会有自定义该类的需求,鉴于此,就不再介绍自定义的实现了。若需要进行自定义,配置SecurityConfigure中配置的方式是auth.parentAuthenticationManager(authenticationManager);,即设置自定义的父级AuthenticationManager

  3. AuthenticationProviderProviderManager认证提供者管理器类,顾名思义,管理了多个认证提供者AuthenticationProvider。前面说过UsernamePasswordAuthenticationFilter定义了Authentication实例的类型,这个类型在这里起到了作用:每一个认证提供者可能支持给当前的登录过滤器提供认证也可能不支持,是否支持的判定就是由Authentication实例的类型决定。遇到任意一个认证提供者AuthenticationProvider支持提供认证,并且判定认证成功,均判定为登录成功。

  4. UserDetailsService:默认配置下,认证提供者管理类下面存在一个名为DaoAuthenticationProvider的认证提供者,该提供者负责了获取用户、验证用户密码(并且内存中加密存储)、更新用户密码加密结果、缓存用户信息等功能。对于获取用户功能,DaoAuthenticationProvider是委托给**UserDetailsService**接口根据用户名获取用户信息,用户密码的加密上是委托PasswordEncoder接口管理,更新用户密码加密结果功能上,先由PasswordEncoder判定是否需要更新加密值,如果需要更新再委托UserDetailsPasswordService完成更新加密值(默认不更新),至于缓存功能,由UserCache接口负责(默认无缓存)。

上面我们了解了UsernamePasswordAuthenticationFilter下的各层次接口,我们就可以通过重新自定义实现这些接口来满足我们实际的生成需求。当然,如果基于用户名密码的过滤器也不能满足需要,大可以自定义登录功能的过滤器,来整体替换或添加登录逻辑。

① 自定义获取用户信息的UserDetailsService

这里实现UserDetailService接口,自定义通过用户名获取用户信息的获取逻辑。

SecurityConfigure.class

@EnableWebSecurity
public class SecurityConfigure extends WebSecurityConfigurerAdapter {
   

    @Autowire
    UserDetailsService detailsService;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        // 这里跟第(Ⅰ)个案例的配置一样,略了,从上面拷下来就行
        ...
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Vue和SpringBoot打造假日旅社管理系统》课程,将讲解如何使用Vue和SpringBoot开发这个项目,手把手演示开发流程!附赠源码、文档、数据库脚本等全部资料,提供售后答疑。 课程简介本课程讲解的是《基于 Vue 和 SpringBoot 的假日旅社管理系统》,该系统支持民宿档案、民宿新闻、民宿预定、民宿评论这四大核心业务,适用于乡村民宿企业的民宿预定业务。系统给每个民宿档案提供一个唯一标识,对民宿预定、评论等各个环节进行快速批量的数据采集,确保游客及时掌握景区民宿的真实数据,方便游客进行民宿预定。另外系统还包括员工管理、组织机构管理、文件管理、权限管理功能,给旅社企业提供更个性化的民宿管理模式。假日旅社管理系统采用了基于角色的访问控制,角色和菜单关联,一个角色可以配置多个菜单权限;然后再将用户和角色关联,一位用户可以赋予多个角色。这样用户就可以根据角色拿到该有的菜单权限,更方便旅社企业的管理人员进行权限管控。   软件技术选型前端Vue:Vue 是构建前端界面的核心框架,本系统采用 2.6.14 版本。View UI:基于 Vue.js2.0 的组件库,本系统采用 4.7.0 版本。后端Spring Boot:构建系统核心逻辑的后端框架,本系统采用 2.7.0 版本。MyBatis / MyBatis Plus:后端连接数据库的框架,本系统采用 3.5.2 版本。数据库MySQL:本项目的主数据库,本系统采用 8.0.29 版本。Redis:本系统采用基于 Windows 版本的 Redis,用于图形验证码和用户菜单权限的临时存储,采用了 5.0.14 版本。开发环境VsCode:项目前端的开发工具,使用版本为 1.68.0。IntelliJ IDEA :项目后端的开发工具,使用版本为 2021.3.2。Jdk:Java 的开发环境,使用版本为 17.0.3.1。Maven:后端项目的打包工具,使用版本为 3.6.2。NodeJs:前端项目的开发环境,使用版本为 16.13.0。 软件架构分析基于 Vue 和 SpringBoot 的假日旅社管理系统包括了系统基础模块、民宿档案模块、民宿新闻模块、民宿预定模块、民宿评论模块这五大功能模块,其架构如下图所示。  接下来,分别对五大模块进行详细介绍。系统基础模块系统基础模块,是用于支撑假日旅社管理系统的正常运行,这个模块包括了登陆注册模块、员工部门管理、菜单权限管理等。假日旅社管理系统支持用户使用账号、密码和图形验证码登陆,操作界面如下图所示。  假日旅社管理系统支持用户使用手机号、姓名、密码和图形验证码注册,操作界面如下图所示。 用户成功进入系统后,可进入到基于 Vue 和 SpringBoot 的假日旅社管理系统的首页,首页展示了当前登陆的地址、现在的时间和用户配置的常用模块,如下图所示。 接着用户点击左侧的用户管理,即可进入用户管理模块,用户管理模块的首页如下图所示。 用户可以在这个模块对系统登陆用户的档案进行维护,包括添加新用户、删除用户、编辑用户、根据姓名/部门查询用户。用户可以进入部门管理模块,管理旅社的部门数据,如下图所示。 同理用户可以进入到菜单管理模块,对系统的菜单进行管理,菜单管理模块的操作界面如下图所示。 民宿档案模块第二个模块是民宿档案模块,民宿档案就是用来管理民宿的数据,民宿档案包括民宿的名称、面积、房号、房间类型、早餐情况、价格、备注等,以下是民宿档案模块的主界面。用户可以点击顶部的“新增”按钮,进入民宿档案添加界面,添加民宿档案数据,如下图所示。 其中房间类型为下拉框单项选择,如下图所示。还有早餐情况也是下拉单选,如下图所示。 用户可以对现有的民宿档案数据进行编辑更新,只需点击每一行民宿档案数据的“编辑”按钮,即可进入民宿档案数据的编辑界面,如下图所示。 用户也可以对不需要的民宿数据进行删除操作,用户点击删除时,系统会弹出二次确认弹框,如下图所示。  民宿新闻模块第三个模块是民宿新闻模块,民宿新闻就是用来管理民宿的新闻资讯,包含的功能如下所示。 民宿新闻包括民宿的名称、面积、房号、房间类型、早餐情况、价格、备注等,以下是民宿新闻模块的主界面,其中的图片仅供测试样例使用。用户可以点击顶部的“新增”按钮,进入民宿新闻添加界面,添加民宿新闻数据,如下图所示。 新闻描述字段采用了 ueditor 富文本编辑器,这是由百度 web 前端研发部开发的所见即所得的开源富文本编辑器,具有轻量、可定制、用户体验优秀等特点,基于 MIT 开源协议,所有源代码可自由修改和使用。 用户可以对现有的民宿新闻数据进行编辑更新,只需点击每一行民宿新闻数据的“编辑”按钮,即可进入民宿新闻数据的编辑界面,如下图所示。 民宿预定模块第四个模块是民宿预定模块,旅客可以在民宿预定模块中预定民宿,达到旅客的住宿目的,民宿预定模块包含的功能如下所示。民宿预定包括了预定民宿 ID、预定民宿名称、预定日期、下单时间、下单人 ID、下单人姓名、价格、是否付款、下单备注等字段,旅客首先进入民宿档案模块,可以看到每一行民宿数据都有一个预约按钮,如下图所示。 如用户点击 1 幢 102 民宿的预约按钮后,会弹出预约确认框,需要输入预约的日期,日期表单默认选择今日,如下图所示。 旅客需要点击“确认预约”按钮,完成预约操作,系统给与“预约成功”提示,如下图所示。 预约成功后,旅客可以从民宿预定模块中进行查询,如下图所示。 最后旅客进行付款操作,点击每一行右侧的付款按钮,如下图所示。支付完成后,系统将预定单的支付状态改为付款,预定流程结束,如下图所示。 民宿评论模块 第五个模块是民宿预定模块,旅客可以在民宿预定结束后评论民宿,以帮助更多的人了解民宿,民宿评论模块包含的功能如下所示。 民宿评论包括了民宿名称、民宿 ID、评论时间、评论内容、评论人 ID、评论人姓名等字段,旅客首先进入民宿档案模块,可以看到每一行民宿数据都有一个评论按钮,如下图所示。 旅客点击评论后,系统给与弹框反馈,如下图所示。  用户输入评论内容后,点击确认评论按钮,即可完成评论操作,如下图所示。  旅客评论后,即可在民宿评论模块中查看此评论数据,如下图所示。 也可以在民宿模块中,双击民宿数据查看评论信息,如下图所示。 项目总结本软件是基于 Vue 和 SpringBoot 的假日旅社管理系统,包含了民宿档案、民宿新闻、民宿预定、民宿评论这四个功能模块。 开发本系统的目的,就是为了帮助旅游景点的民宿企业提高民宿管理效率,降低人力成本,让旅游景点的民宿企业获得更多的经济效益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值