Spring Security

Posted 埋年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Security相关的知识,希望对你有一定的参考价值。

一、什么是Spring Security?
SpringSecurity是基于Spring AOP和Servlet过滤器的安全框架。它提供全面的安全性解决方案,同时在Web 请求级和方法调用级处理身份确认和授权。在 Spring Framework 基础上,Spring Security 充分利用了依赖注入(DI,Dependency Injection)和面向切面编程(AOP)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。它是一个轻量级的安全框架,它确保基于Spring的应用程序提供身份验证和授权支持。它与Spring MVC有很好地集成,并配备了流行的安全算法实现捆绑在一起。安全主要包括两个操作“认证”与“验证”(有时候也会叫做权限控制)。“认证”是为用户建立一个其声明的角色的过程,这个角色可以一个用户、一个设备或者一个系统。“验证”指的是一个用户在你的应用中能够执行某个操作。在到达授权判断之前,角色已经在身份认证过程中建立了。*
我们简单来理解一下上面这段话:
第一:什么是Spring Security ?
Spring Security是一个安全框架。
第二:Spring Security核心功能?
(1)认证(你是谁,用户/设备/系统)
(2)验证(你能干什么,也叫权限控制/授权,允许执行的操作)
(3)攻击防护(防止伪造身份)
第三:Spring Security原理技术
Filter、Servlet、Spring DI、SpringAOP

首先我们要创造一个springboot项目

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

项目创建成功后在pom.xml 中添加thymeleaf 依赖

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

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

然后添加登录页面和主页面和需要通过权限访问的页面,
在这里插入图片描述
index.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 sec:authorize="isAuthenticated()">
                <a class="item">
                    用户名:<span sec:authentication="name"></span>
                 <!--   角色:<span sec:authentication="principal.getAuthorities()"></span>-->
                </a>
            </div>
            <div sec:authorize="isAuthenticated()">
                <a class="item" th:href="@{/logout}">
                    <i class="sign-out icon"></i> 注销
                </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>

login.html

登录
<div class="ui segment">

    <div style="text-align: center">
        <h1 class="header">登录</h1>
    </div>

    <div class="ui placeholder segment">
        <div class="ui column very relaxed stackable grid">
            <div class="column">
                <div class="ui form">
                    <form th:action="@{/login}" method="post">
                        <div class="field">
                            <label>Username</label>
                            <div class="ui left icon input">
                                <input type="text" placeholder="Username" name="user">
                                <i class="user icon"></i>
                            </div>
                        </div>
                        <div class="field">
                            <label>Password</label>
                            <div class="ui left icon input">
                                <input type="password" name="pass">
                                <i class="lock icon"></i>
                            </div>
                        </div>
                        <div class="field">
                            <input type="checkbox" name="remember"> 记住我
                        </div>
                        <input type="submit" class="ui blue submit button"/>
                    </form>
                </div>
            </div>
        </div>
    </div>

    <div style="text-align: center">
        <div class="ui label">
            </i>注册
        </div>
        <br><br>
        <small>blog.kuangstudy.com</small>
    </div>
    <div class="ui segment" style="text-align: center">
        <h3>Spring Security Study by 秦疆</h3>
    </div>
</div>

level1 1.html

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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="@{/qinjiang/css/qinstyle.css}" rel="stylesheet">
    
</head>

<body>

<!--主容器-->

<div class="ui container">

    <div th:replace="~{index::nav-menu}"></div>

    <div class="ui segment" style="text-align: center">
        <h3>Level-1-1</h3>
    </div>

</div>


<script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}"></script>
<script th:src="@{/qinjiang/js/semantic.min.js}"></script>

</body>
</html>

level1 2.html

	<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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="@{/qinjiang/css/qinstyle.css}" rel="stylesheet">
</head>
<body>

<!--主容器-->
<div class="ui container">
    <div th:replace="~{index::nav-menu}"></div>
    <div class="ui segment" style="text-align: center">
        <h3>Level-1-2</h3>
    </div>
</div>
<script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}"></script>
<script th:src="@{/qinjiang/js/semantic.min.js}"></script>

</body>
</html>

其他页面都是这样,改变一下h3标签里面的信息就行了,就是用来做测试而已
控制器添加我们访问页面的路劲

@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;
}

并在我们的properties中配置一个关闭缓存的功能
spring.thymeleaf.cache=false
thymeleaf是一个模板引擎,缓存的意思是加载一次模板之后便不会在加载了,对于生产环境应该加上缓存,但是在开发过程中如果打开缓存,不方便开发人员调试。试想一下,改一行html,就需要重启服务器,肯定是不方便的。总结一下:本地开发环境下,需要把缓存关闭,否则调试成本太大。其他环境下缓存都需要打开。
然后我们添加我们的security依赖

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

搭配好上面的环境,我们就开始配置类,先创建一个config包用来装我们的配置,
然后创建一个类 SecurityConfig ,让他继承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");
		
	//没有权限默认回到登录页面,需要开启登录的页面
	http.formLogin();

}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //这些数据正常应该从数据库中读
    auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
            .withUser("ajie").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
            .and()
            .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
}

认证完成后
然后在configure(HttpSecurity http)在添加注销功能
//注销,开启了注销功能
http.logout();

然后在页面写一个注销按钮,给一个默认的logout路径。
跳到首页
http.logout().logoutSuccessUrl("/");

完成登录注销后,我们去调整一下我们的页面,我们登录成功时应该显示注销按钮,没有登录的时候就显示我们的登录按钮,怎么才能做到这种效果呢,我们先在pom.xml中添加thymeleaf整合security的依赖

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

然后在页面使用我们的thymeleaf整合security,通过它来判断我们什么时候该显示什么,

<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">
        用户名:<span sec:authentication="name"></span>
     <!--   角色:<span sec:authentication="principal.getAuthorities()"></span>-->
    </a>
</div>
<div sec:authorize="isAuthenticated()">
    <a class="item" th:href="@{/logout}">
        <i class="sign-out icon"></i> 注销
    </a>
</div>

如果上面的用户名显示不出来,那我们可以把我的springboot的版本降低成 : 2.0.9.RELEASE

修改之后我们的数据就能正常显示了,然后我们点击注销,再次登录,我们就会发现报错,然后我们需要在我们配置类权限添加一下代码
http.csrf().disable();

以上是关于Spring Security的主要内容,如果未能解决你的问题,请参考以下文章

oauth2 spring-security 如果您在请求令牌或代码之前登录

Spring Security问题

Spring Security:如何获取自动渲染的登录页面代码?

spring security 匿名访问安全吗

springboot集成spring security实现restful风格的登录认证 附代码

未调用 Spring Security j_spring_security_check