SpringBoot:SpringSecurity

SpringSecurity

在Web开发中,安全第一位。

安全不是一个功能性需求,也就是说如果不设置安全方面的功能,网站也一样能跑起来。

安全应该在什么时候考虑起来呢?应该在设计之初,因为不能存在安全的问题,比如网站漏洞,隐私泄露等,而且一旦架构确定,增加安全可能需要改动一些代码,所以在设计网站开发的一开始,就要考虑安全的问题。

涉及到安全方面的框架有Shiro和SpringSecurity,它们是很相似的,功能差不多类似,都有认证和授权这两个主要的功能。

SpringSecurity是一个强大的并且可定制化的身份认证和权限控制的框架

Spring Security是针对Spring项目的安全框架,也是SpringBoot底层安全模块默认的技术选型,它可以实现强大的Web安全控制。

以前我们做安全的时候用的都是拦截器,过滤器,有大量的原生代码,是很冗余的,我们从MVC框架到Spring然后到SpringBoot都是一路在简化代码,SpringSecurity也是抱着这样的目的。

创建一个新的SprngBoot项目,这里引用了web依赖和themleaf的依赖。

导入素材,几个页面和css,js,这里供测试的素材来自于秦老师,素材是一个简单的demo,这个demo用于权限功能的展示,首页仅有一个登录链接,跳向一个登录页面,以及三个Level的链接,跳向levelx-x的页面,里面仅仅是levelx-x的一段文字。我们在自己的项目里写一个路由功能的Controller,用于页面跳转,然后启动SpringBoot。
我们想要达到的效果:Level3的页面level1,level2是不能访问的;登录以后应该仅看到level等级对应的内容,而不是全部内容。

我们对权限的控制是基于AOP的思想横切进去,跟我们原来的功能代码无关。

配置SpringSecurity

我们仅需要引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理。

从SpringBoot的官网上可以找到教程,具体参见  Securing a Web Application 以及Spring Security Reference

需要记住三个类

  • WebSecurityConfiguationAdapter: 自定义Security策略
  • AuthenticationMangerBuilder:自定义认证策略
  • @EnableWebSecurity:开启WebSecurity策略

Spring Security的两个主要目的是 认证授权(访问控制)

这个概念是通用的,而不只是在Spring Security存在,Shiro也是基于这种思想。

  • 导入依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
  • 自定义Security策略

自定义配置需要用到一个自定义的Config类,来继承WebSecurityConfiguationAdapter。

重写WebSecurityConfiguationAdapter的configure(HttpSecurity)方法,它可以定义哪些URL路径可以被保护,哪些路径不需要被保护。

👇是网页翻译spring官方文档得来的结果,写的还蛮详细。

所以现在我们来写一个 自定义的Config,继承了WebSecurityConfigurerAdapter 类,然后重写configure(HttpSecurity)方法,这个方法的主要作用是授权,它定义了哪些URL路径应该被保护,http.formLogin()的方法定义了没有权限会跳向登录页面。

/**
 * 自定义Security策略
 * WebSecurityConfig类使用@EnableWebSecurity进行注释,以启用Spring Security的web安全支持并提供Spring MVC集成。
 * 它还扩展了WebSecurityConfigurerAdapter并覆盖了它的一些方法来设置web安全配置的一些细节。
 *
 * @author Claw
 */
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 授权
     * configure(HttpSecurity)方法定义了哪些URL路径应该保护,哪些不应该保护。
     * 具体来说,将 /和首页路径配置为不需要任何身份验证。所有其他路径都必须经过身份验证。
     * 如果用户验证失败,页面将被重定向到/login?error,页面将显示相应的错误消息。
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 请求授权的规则
         */
        http
             .authorizeRequests().antMatchers("/").permitAll()
             .antMatchers("/level1/**").hasRole("vip1")
             .antMatchers("/level2/**").hasRole("vip2")
             .antMatchers("/level3/**").hasRole("vip3");
        //没有权限会跳向登录页面,需要开启登录的页面
        http.formLogin();
    }
}

当定义好它以后,启动SpringBoot,进入首页没有问题,但再点击leve的页面就需要权限认证了,它会带我们去向Security自己的登录页面,而不是自己写的登录页面。

现在我们需要用户名和密码来登录,这个需要我们自己来定义,通常来说,是从数据库来获取角色和密码,但是现在它提供了一个方法,可以让我们把用户存放在内存中。

HttpSecurity的源码注释非常详细,它教我们如何去使用。

需要重写configure(AuthenticationManagerBuilder auth)这个方法,需要注意在SpringSecurity 5.0+中新增了很多加密方法 它会要求password进行密码加密,如果不这么做的话,在点击登录的时候会报一个passwordEncoder为null的错误,加密的方式有很多种,这里使用了BCryptPasswordEncoder()提供的加密方式。

补充:在查看官方文档的时候发现官方推荐的是 DelegatingPasswordEncoder这个类提供加密方式。

定义的vip3等级最高,它可以扮演vip1,vip2,vip3的角色,访问所有页面,vip2包括了vip1的角色,能访问level1和level2的所有页面,vip1只有vip1角色的授权,只能访问level1的页面。

 /**
     * 认证
     * springboot 2.1.x可以直接使用
     * 在SpringSecurity 5.0+中新增了很多加密方法 它会要求password进行密码加密
     * inMemoryAuthentication在内存中设置用户和密码和所对应的角色。
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //inMemoryAuthentication是从内存中存放数据来使用,正常应该是从数据库取
        //如果从数据库取数据,应该用到是auth.jdbcAuthentication这个方法
        auth
            .inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
            .withUser("vip1").password(new BCryptPasswordEncoder().encode("123")).roles("vip1")
            .and().withUser("vip2").password(new BCryptPasswordEncoder().encode("123")).roles("vip2", "vip1")
            .and().withUser("vip3").password(new BCryptPasswordEncoder().encode("123")).roles("vip3", "vip1", "vip2");
        auth.jdbcAuthentication();
    }

定义以后启动测试 点击level1的界面,需要认证,登录以后进入了level-1-1的页面,ok没问题,level-1-2的也没问题。但进入level2就报出了403的错误,因为拿了vip1的账号的登录,权限只有level1的页面可以进入。

接下来我们考虑下注销的事情,http对象里当然也有注销的方法,并且非常简单,HttpSecurity这个类的注释也仍然详细。

于是在confgure方法加入这两行就好了,添加了注销功能,并且在注销成功后重定向到首页。

http //注销
    .logout()
    //注销成功后重定向到指定页面
    .logoutSuccessUrl("/");

 目前首页并没有注销的功能,注释里有说到访问/logout就是注销的访问路径,那么只需要在首页添加注销的访问路径就好了。

             <!--注销-->
                <a class="item" th:href="@{/logout}">
                    <i class="sign-out  icon"></i> 注销
                </a>

security有csrf防护(跨站请求伪造)功能,这会让在注销的时候报出404的错误。官方文档说了为了防止伪造注销请求,应该保护注销HTTP请求不受CSRF攻击。防止伪造注销请求是必要的,这样恶意用户就无法读取受害者的敏感信息。

在请求注销的时候可以使用post请求,或者在仅在学习的时候关闭这个功能

  //关闭csrf
  http.csrf().disable();

测试,图是后来录的,此时已经写完了展示对应权限的功能,注销成功后已经看不到level模块的内容。

 

 目前为止的登录页面是security自己自带的页面,访问路径为/login 把它换成我们自己写的页面的话使用http对象的方法即可。

        //没有权限会跳向登录页面,需要开启登录的页面
        http
             .formLogin()
             .loginPage("/toLogin");

当然对应的HTML中表单的action的访问路径也要改成我们自己定义的。

                    <div class="ui form">
                        <form th:action="@{/toLogin}" method="post">
                            <div class="field">
                                <label>Username</label>
                                <div class="ui left icon input">
                                    <input type="text" placeholder="Username" name="username">
                                    <i class="user icon"></i>
                                </div>
                            </div>
                            <div class="field">
                                <label>Password</label>
                                <div class="ui left icon input">
                                    <input type="password" name="password">
                                    <i class="lock icon"></i>
                                </div>
                            </div>
                            <input type="submit" class="ui blue submit button"/>
                        </form>
                    </div>

SpringSecurity整合Thymeleaf

接下来需要做的事情就是使具有对应权限的用户只看到对应权限的页面,也就是vip1只能看到level1的页面,vip3能看见leve1,2,3的页面。

以前通常通过模板引擎的if标签来判断,jsp的话能够从Session里面来取得用户数据然后在页面通过if标签来进行判断哪些页面能够展示。

Thymeleaf当然也可以,它还可以与Secuirty整合,不过这不是一个常见的用法。

需要导入thymeleaf和security的整合包,有版本的差异,需要注意自己Security的版本,因为我是5.0以上,所以我选择了 thymeleaf-extras-springsecurity5 

        <!--thymeleaf和security的整合-->
        <!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 -->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>

 

现在在首页加上权限判断:如果未登录,显示登录功能;如果已登录,显示用户名和权限。

首先不要忘记添加命名空间的约束。

<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>

thymeleaf与security的整合后在本次学习中用到的几个方法

<!-- 是否登陆 -->
<div sec:authorize="isAuthenticated()">
<!-- 用户姓名 -->
<span sec:authentication="name"></span>
<!-- 用户权限 -->
<span sec:authentication="principal.authorities"></span>

在Html中进行判断

 <div class="ui segment" id="index-header-nav" th:fragment="nav-menu">
        <div class="ui secondary menu">
            <a class="item" th:href="@{/index}">首页</a>

            <!--登录注销-->
            <div class="right menu">
                <!--如果没有被认证(登录):显示登录功能-->
                <div sec:authorize="!isAuthenticated()">
                    <a class="item" th:href="@{/toLogin}">
                        <i class="address card icon"></i> 登录
                    </a>
                </div>
                <!--如果已认证(登录),显示用户名,权限-->
                <div class="right menu"sec:authorize="isAuthenticated()">
                    用户名:<span sec:authentication="name"></span>
                    权限:<span sec:authentication="principal.authorities"></span>
                    <!--是否登录-->
                </div>
                <div class="right menu" sec:authorize="isAuthenticated()">
                    <a class="item" th:href="@{/logout}">
                        <i class="sign-out  icon"></i> 注销
                    </a>
                </div>

            </div>
        </div>
    </div>

未登录

 

已登录 

实现这个后,我们可以实现权限对应的页面展示了,用到了sec:authorize="hasRole()”方法来判断是否有对应的权限。

    <div>
        <br>
        <div class="ui three column stackable grid">
            <div class="column">
                <!--Vip1用户对应的页面-->
                <div class="ui raised segment" sec:authorize="hasRole('vip1')">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 1</h5>
                            <hr>
                            <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                            <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                            <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
                        </div>
                    </div>
                </div>
            </div>
            <!--Vip2用户对应的页面-->
            <div class="column">
                <div class="ui raised segment" sec:authorize="hasRole('vip2')">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 2</h5>
                            <hr>
                            <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                            <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                            <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
                        </div>
                    </div>
                </div>
            </div>
            <!--Vip3用户对应的页面-->
            <div class="column">
                <div class="ui raised segment" sec:authorize="hasRole('vip3')">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 3</h5>
                            <hr>
                            <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                            <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                            <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

        </div>
    </div>

 再测试:vip1就只能看见leve1的内容啦 😁

总结:如何使用SpringSecurity?

  • 导入SpringSecurity的依赖
  • 定义HttpSecurity策略
    • 哪些路径可以访问,哪些路径不可以访问。
    • 登录路径
    • 注销
  • 定义Authentication策略
    • 用户所对应的权限
    • 用户名和密码的设置,可以定义在内存,也可以从数据库获取(通常)
  • SpringSecurity和thymeleaf的整合
    • 页面进行权限的判断

参考:【狂神说Java】SpringBoot最新教程IDEA版通俗易懂 

素材通过秦老师的学习群获得。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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 的假日旅社管理系统,包含了民宿档案、民宿新闻、民宿预定、民宿评论这四个功能模块。 开发本系统的目的,就是为了帮助旅游景点的民宿企业提高民宿管理效率,降低人力成本,让旅游景点的民宿企业获得更多的经济效益。
Spring Boot可以使用Spring Security来提供声明式的安全访问控制解决方案。为了在Spring Boot使用Spring Security,你需要引入相应的依赖。在pom.xml文件添加以下依赖项: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 这个依赖项会为你提供Spring Security的功能。然后,你可以在应用程序的配置文件(通常是application.yml或application.properties)配置Spring Security的相关属性。在配置文件,你可以指定用户的账号和密码,以及拥有的角色。例如,在application.yml文件可以添加以下内容: spring: security: user: name: user password: user roles: ADMIN 这样配置之后,你的Spring Boot应用程序就会使用Spring Security进行安全访问控制了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [springboot使用springsecurity](https://blog.csdn.net/wang0907/article/details/121191587)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [SpringBootSpring Security 的使用](https://blog.csdn.net/CSH__/article/details/126008591)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值