zoukankan      html  css  js  c++  java
  • 7、spring security安全框架学习

    前言:

      在 Web 开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的初期就考虑进来。如果在应用开发的后期才考虑安全的问题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一方面,应用的基本架构已经确定,要修复安全漏洞,可能需要对系统的架构做出比较重大的调整,因而需要更多的开发时间,影响应用的发布进程。因此,从应用开发的第一天就应该把安全相关的因素考虑进来,并在整个应用的开发过程中。

      Java Web项目的权限管理框架,目前有两个比较成熟且使用较多的框架,Shiro 和 Spring Security ,Shiro 比 Spring Security更加轻量级,但是需要手动配置的东西较多,Spring Security 和 Spring 集成更好,甚至直接适配了Spring Boot。

    学习springsecurity用到的pom.xml依赖:

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!--spring-security依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <!--security跟Thymeleaf整合-->
            <dependency>
                <groupId>org.thymeleaf.extras</groupId>
                <artifactId>thymeleaf-extras-springsecurity5</artifactId>
                <version>3.0.4.RELEASE</version>
            </dependency>
        </dependencies>
    View Code

    一、springsecurity入门学习


    1、准备测试数据

      这里我准备的是一个首页一个登录页面,以及三个vip等级对应的3个页面、

      静态资源放到static目录下、views放到templates下

      下载链接:https://files.cnblogs.com/files/zhangzhixi/SpringBoot-SpringSecurity%E7%B4%A0%E6%9D%90.rar

    2、认识SpringSecurity

      Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!

    记住几个类:

    • WebSecurityConfigurerAdapter:自定义Security策略
    • AuthenticationManagerBuilder:自定义认证策略
    • @EnableWebSecurity:开启WebSecurity模式

    1、引入 Spring Security 模块

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-security</artifactId>
    </dependency>  

      加入依赖后,会自动获取Spring Security 5.1.5版本的Jar包:

    然后,,一个基本的Spring Security已经有了,然后打开浏览器,访问http://localhost:8080,神奇的出来了一个登录页面,但是并没有创建任何的html文件、

     2、登录名以及密码

    登录security提供的默认login页面:

      username:user

      password:是在控制台打印的一串UUID

    然后就可以登录到我们的首页了。

    3、基础配置类


       编写了配置类,security的默认配置就不会生效了(不会直接跳转到login页面,而是直接访问主页)、依照我们自己的配置来:

    • 定义请求的授权规则:
    @EnableWebSecurity // 开启WebSecurity模式
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 定制请求的授权规则
            // 首页所有人可以访问
            http.authorizeRequests().antMatchers("/").permitAll()
                    .antMatchers("/level1/**").hasRole("vip1")
                    .antMatchers("/level2/**").hasRole("vip2")
                    .antMatchers("/level3/**").hasRole("vip3");
        }
    }

    测试一下:发现除了首页,都进不去了!因为我们目前没有登录的角色,因为请求需要登录的角色拥有对应的权限才可以!

    • 在configure()方法中加入以下配置,开启自动配置的登录功能!
    // 没有权限默认会到登录页面,需要开启登录功能!
    http.formLogin();

      此时如果没有权限就会跳转至登陆页

    • 定义认定规则,重写configure(AuthenticationManagerBuilder auth)方法
    //认证
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //数据正常应该从数据库中取,现在从内存中取
            auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                    // 设置用户名密码以及能够访问的权限设置
                    .withUser("admin").password(new BCryptPasswordEncoder().encode("123")).roles("vip1", "vip2")
                    .and()
                    .withUser("root").password(new BCryptPasswordEncoder().encode("123")).roles("vip1", "vip2", "vip3")
                    .and()
                    .withUser("guest").password(new BCryptPasswordEncoder().encode("123")).roles("vip1");
        }
    

    就是说我们能够访问首页,如果想进入到别的页面就需要登录:

      什么用户对应什么权限,比如我使用了admin用户登录成功后,可以访问vip1和vip2的页面,但是访问不了vip3的页面!

    这里设置密码加密auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
    否则会报There is no PasswordEncoder mapped for the id"null"错误,
    创建的每个用户也必须添加密码加密**.password(new BCryptPasswordEncoder().encode("123"))**
    

    4、注销以及权限控制


    注销:

    1、开启自动配置的注销功能:

    //定制请求的授权规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       //....
       //开启自动配置的注销的功能
          // /logout 注销请求
       http.logout();
    }
    

    2、前端页面添加注销按钮

    <a class="btn btn-primary" th:href="@{/logout}">注销</a>
    

    3、测试发现,点击注销按钮后会跳转到登陆页面,此时想要在注销成功后跳转到指定页面需要在请求后添加.logoutSuccessUrl("/");

    // .logoutSuccessUrl("/"); 注销成功来到首页
    http.logout().logoutSuccessUrl("/");
    

    权限控制: 

    需求:

      用户没有登录的时候,导航栏上只显示登录按钮

      用户登录之后,导航栏可以显示登录的用户信息及注销按钮!

      还有就是,比如admin这个用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能,而vip1的功能菜单不显示!

    1、导入依赖

    !--security跟Thymeleaf整合-->
    dependency>
       <groupId>org.thymeleaf.extras</groupId>
       <artifactId>thymeleaf-extras-springsecurity5</artifactId>
       <version>3.0.4.RELEASE</version>
    /dependency>
    

    2、index页面导入命名空间

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

    3、修改index页面,增加判断(是否已登录)

    <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" sec:authorize="!isAuthenticated()">
                    <a class="item" th:href="@{/login}">
                        <i class="address card icon"></i> 登录
                    </a>
                </div>
    
                <!--已登录,显示登录用户以及注销按钮-->
                <div class="right menu" sec:authorize="isAuthenticated()">
    
                    用户名:<p sec:authentication="name"></p>
                    角色:<p sec:authentication="principal.authorities"></p>
    
                    <a class="item" th:href="@{/logout}">
                        <i class="address card icon"></i> 注销
                    </a>
                </div>
            </div>
        </div>

    4、修改index页面,增加判断(显示哪个用户对应的页面)

    <!--如果登录用户拥有这个角色,则显示该div内的内容,如果没有则不显示-->
    <div class="column" sec:authorize="hasAnyRole('vip1')">
        <div class="ui raised segment">
            <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>

    比如admin用户只有vip1跟vip2的权限,那么页面上只显示vip1跟vip2的页面信息

     5、记住我以及首页定制


     记住我功能:

    //定制请求的授权规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    //。。。。。。。。。。。
       //记住我,保存2周
       http.rememberMe();
    }
    

    测试,关闭浏览器再次打开用户依旧存在

    本质上是保存到cookie,通过浏览器审查元素的application中可以看到

    定制登录页:

    index.html、controller、还有login.html的请求都要改成/toLogin,否则无法跳转到自定义的login页面

    // 没有权限默认会到登录页面,开启登录功能!
    http.formLogin().loginPage("/toLogin"); // 定制登录页面
    

      但是我们的自定义的登录页面没有记住我功能,所以要在登录页面添加记住我功能选框,并在configure将标签的name属性接收

      login的form表单:

     1 <form th:action="@{/toLogin}" method="post">
     2     <div class="field">
     3         <label>Username</label>
     4         <div class="ui left icon input">
     5             <input type="text" placeholder="Username" name="username">
     6             <i class="user icon"></i>
     7         </div>
     8     </div>
     9     <div class="field">
    10         <label>Password</label>
    11         <div class="ui left icon input">
    12             <input type="password" name="password">
    13             <i class="lock icon"></i>
    14         </div>
    15         <input type="checkbox" name="remember">记住我
    16     </div>
    17     <input type="submit" class="ui blue submit button"/>
    18 </form>

      configure接收表单传来的值

    // 记住我功能,cookie保存时间2周
    http.rememberMe().rememberMeParameter("remember");
    

     

  • 相关阅读:
    树莓派系统Raspbian安装小结
    树莓派安装centos 7系统
    Ubuntu下安装SSH服务
    使用xUnit为.net core程序进行单元测试(4)
    使用xUnit为.net core程序进行单元测试(3)
    使用xUnit为.net core程序进行单元测试 -- Assert
    使用xUnit为.net core程序进行单元测试(1)
    用 Identity Server 4 (JWKS 端点和 RS256 算法) 来保护 Python web api
    asp.net core 2.0 查缺补漏
    "软件随想录" 读书笔记
  • 原文地址:https://www.cnblogs.com/zhangzhixi/p/14340219.html
Copyright © 2011-2022 走看看