springboot(17)——集成SpringSecurity(安全)

1 集成SpringSecurity

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

市面上存在比较有名的:Shiro,Spring Security ;认证,授权

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它实际上是保护基于spring的应用程序的标准。
Spring Security是一个框架,侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring安全性的真正强大之处在于它可以轻松地扩展以满足定制需求。

功能权限
访问权限
菜单权限
…拦截器,过滤器:大量的原生代码~冗余

Spring官方文档:找到我们对应的版本 https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter
1 导入thymeleaf的依赖

<dependency>
		<groupId>org.thymeleaf</groupId>
		<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
		<groupId>org.thymeleaf.extras</groupId>
		<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

2 环境搭建
在这里插入图片描述
其中RouterController.java

package com.zs.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RouterController {
    
    
    @RequestMapping({
    
    "/","/index"})
    public String index() {
    
    
        return "index";
    }

    @RequestMapping("toLogin")
    public String toLogin() {
    
    
        return "views/login";
    }

    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id) {
    
    
        return "views/level1/"+id;
    }
    @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id") int id) {
    
    
        return "views/level2/"+id;
    }
    @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id") int id) {
    
    
        return "views/level3/"+id;
    }

}

运行结果
在这里插入图片描述
3 用户认证和授权
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理
记住几个类:

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

Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
“认证”(Authentication)
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
这个概念是通用的,而不是只在Spring Security 中存在。

导入依赖

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

官方文档 https://docs.spring.io/spring-security/site/docs/5.3.0.RELEASE/reference/html5/
4 编写 Spring Security 配置类

package com.zs.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

//aop拦截器
@EnableWebSecurity
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");

        // 没有权限会默认到登录页面,需要开启登录的页面 这个也页面是远程的
        // login
        http.formLogin();

    }

    // 认证的规则,sprintboot2.1.x 是可以直接使用
    // 密码编码:passwordEncoder
    // 在spring Security 5.0+ 新增了很多加密方式
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
    
//        super.configure(auth);
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("zs").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");

    }
}

在这里插入图片描述
测试
在这里插入图片描述
5 注销及权限控制
开启自动配置的注销的功能

// 开启注销功能,跳到首页
        http.logout().logoutSuccessUrl("/");

前端操作——添加注销按钮

<a class="item" th:href="@{/logout}">
   <i class="address card icon"></i> 注销
</a>

登录成功后点击注销,发现注销完毕会跳转到登录页面

我们现在又来一个需求:
1 用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮!
2 还有就是,比如zs这个用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能,而vip1的功能菜单不显示!这个就是真实的网站情况了!该如何做呢?
我们需要结合thymeleaf中的一些功能
sec:authorize=“isAuthenticated()”:是否认证登录!来显示不同的页面

依赖导入

<dependency>
     <groupId>org.thymeleaf.extras</groupId>
     <artifactId>thymeleaf-extras-springsecurity5</artifactId>
     <version>3.0.4.RELEASE</version>
 </dependency>

修改前端页面
导入命名空间

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"

修改导航栏,增加认证判断
在这里插入图片描述

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>首页</title>
    <!--semantic-ui-->
    <link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet">
    <link th:href="@{/css/mystyle.css}" rel="stylesheet">
</head>
<body>


<!--主容器-->
<div class="ui container">

    <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 sec:authorize="isAuthenticated()">
                <a class="item" th:href="@{/logout}">
                    <i class="address card icon"></i> 注销
                </a>
                </div>

                <div sec:authorize="isAuthenticated()">
                    <a class="item">
                        <i class="address card icon"></i>
                        用户名:<span sec:authentication="principal.username"></span>
                        角色:<span sec:authentication="principal.authorities"></span>
                    </a>
                </div>


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

    <div class="ui segment" style="text-align: center">
        <h3>Spring Security Study by 秦疆</h3>
    </div>

    <div>
        <br>
        <div class="ui three column stackable grid">
            <div class="column" sec:authorize="hasRole('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>

            <div class="column" sec:authorize="hasRole('vip2')">
                <div class="ui raised segment">
                    <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>

            <div class="column" sec:authorize="hasRole('vip3')">
                <div class="ui raised segment">
                    <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>
    
</div>
<script th:src="@{/js/jquery-3.1.1.min.js}"></script>
<script th:src="@{/js/semantic.min.js}"></script>

</body>
</html>

测试
在这里插入图片描述
6 记住我
现在的情况,我们只要登录之后,关闭浏览器,再登录,就会让我们重新登录,但是很多网站的情况,就是有一个记住密码的功能,这个该如何实现呢?很简单
开启记住我功能

  // 记住我 cookie 默认记住两周
        http.rememberMe();

我们可以查看浏览器的cookie
在这里插入图片描述
7 定制登录页
现在这个登录页面都是spring security 默认的,怎么样可以使用我们自己写的Login界面呢?
刚才的登录页配置后面指定 loginpage

@RequestMapping("/toLogin")
public String toLogin() {
    
    
    return "views/login";
}
 // 没有权限会默认到登录页面,需要开启登录的页面 这个页面是远程的
        // login 定制登录页
        http.formLogin().loginPage("/toLogin");

前端也需要指向我们自己定义的 login请求
index.html

  <div sec:authorize="!isAuthenticated()">
    <a class="item" th:href="@{/toLogin}">
       <i class="address card icon"></i> 登录
    </a>
</div>

我们登录,需要将这些信息发送到哪里,我们也需要配置
login.html

<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>

逻辑
在这里插入图片描述
8 在登录页增加记住我的多选框

<div class="field">
   <input type="checkbox" name="remember"> 记住我
</div>

SecurityConfig.java

//定制记住我的参数!
http.rememberMe().rememberMeParameter("remember");

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zs18753479279/article/details/112705589