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");

 

 

 

 

posted @ 2021-01-28 15:52  Java小白的搬砖路  阅读(168)  评论(0编辑  收藏  举报