SpringBoot项目整合SpringSecurity

SpringSecurity官网介绍:

1 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。
2 
3 Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring Security的真正强大之处在于可以轻松扩展以满足自定义要求

看了上面的介绍,可以知道SpringSecurity的主要功能就是:身份验证 和 权限控制

下面带大家进一步了解SpringSecurity的使用以及实现的过程

1、构建初始SpringBoot项目

1.1创建空项目

1.1.1选择SpringBoot项目

1.1.2项目命名

 自动配置我们只选择Spring Web,其余的依赖自己来,为了方便控制

 

 导入依赖

 1         <!--thymeleaf整合security-->
 2         <dependency>
 3             <groupId>org.thymeleaf.extras</groupId>
 4             <artifactId>thymeleaf-extras-springsecurity4</artifactId>
 5             <version>3.0.4.RELEASE</version>
 6         </dependency>
 7         <!--security -->
 8         <dependency>
 9             <groupId>org.springframework.boot</groupId>
10             <artifactId>spring-boot-starter-security</artifactId>
11         </dependency>
12         <!--thymeleaf-->
13         <dependency>
14             <groupId>org.thymeleaf</groupId>
15             <artifactId>thymeleaf-spring5</artifactId>
16         </dependency>
17         <dependency>
18             <groupId>org.thymeleaf.extras</groupId>
19             <artifactId>thymeleaf-extras-java8time</artifactId>
20         </dependency>
21         <!--以下为系统系统自动导入,无需再次导入-->
22         <dependency>
23             <groupId>org.springframework.boot</groupId>
24             <artifactId>spring-boot-starter-web</artifactId>
25         </dependency>

好啦,现在总算把一个空项目新建完成了,接下来导入静态资源,这里我们提供一个网盘链接:

https://pan.baidu.com/s/1GlTmHAf2mmOuZc53Uf6jTQ
提取码:ypxc

大家可以自取,都是一些简单的页面和项目所需的css,js

新建一个Controller自测一下:

 1 package com.ldk.controller;
 2 
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.web.bind.annotation.RequestMapping;
 5 import org.springframework.web.bind.annotation.ResponseBody;
 6 
 7 /**
 8  * @Author: ldk
 9  * @Date: 2020/5/19 21:44
10  * @Describe:
11  */
12 @Controller
13 public class testController {
14 
15     @RequestMapping("/hello")
16     @ResponseBody
17     public String hello(){
18         return "hello SpringSecurity";
19     }
20 }

项目总体结构如图:

 启动项目,访问:http://localhost:8080/hello,又看到熟悉的:

 这证明这个简单的Web项目可以跑通。

3、新建路由Controller

 1 package com.ldk.Controller;
 2 
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.web.bind.annotation.PathVariable;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 
 7 /**
 8  * @Author: ldk
 9  * @Date: 2020/5/19 12:55
10  * @Describe:
11  */
12 @Controller
13 public class RouterController {
14 
15     @RequestMapping({"/","/index"})
16     public String index21(){
17         return "index";
18     }
19     @RequestMapping("/toLogin")
20     public String ind1ex(){
21         return "views/login";
22     }
23 
24     @RequestMapping("/level1/{id}")
25     public String ind1ex1(@PathVariable("id")int id){
26         return "views/level1/"+id;
27     }
28     @RequestMapping("/level2/{id}")
29     public String ind1ex2(@PathVariable("id")int id){
30         return "views/level2/"+id;
31     }
32     @RequestMapping("/level3/{id}")
33     public String ind1ex3(@PathVariable("id")int id){
34         return "views/level3/"+id;
35     }
36 
37 }

4、上主菜(配置SecurityConfig)

我们都知道,无论SpringBoot或者SpringCloud与其他框架集成,都必须先导包,在创建Config类进行配置,然后加一个类似于@Enablexxx的注解,即可使用,SpringBoot集成SpringSecurity也不例外,这一步我们先创建一个空的SecurityConfig类  并集成 WebSecurityConfigurerAdapter 类,并重写他里面的两个方法,这里我们解释一下:WebSecurityConfigurerAdapter 类是个适配器, 在配置的时候,需要我们自己写个配置类去继承他,然后编写自己所特殊需要的配置,我们重写一下它的 认证 和 授权 方法,来实现自己的定制化个性服务。

在SpringSecurityApplication同级目录下新建config文件夹,并新建SecurityConfig配置类:

 1 package com.ldk.config;
 2 
 3 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 4 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 5 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 6 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 7 
 8 /**
 9  * @Author: ldk
10  * @Date: 2020/5/19 13:38
11  * @Describe:
12  */
13 
14 @EnableWebSecurity
15 public class SecurityConfig extends WebSecurityConfigurerAdapter {
16 
17     //授权
18     @Override
19     protected void configure(HttpSecurity http) throws Exception {
20     }
21 
22     //认证
23     @Override
24     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
25     }
26 
27 }

。现在访问以下http://localhost:8080/  顺利跳转首页,这个时候,首页的level1,level2,level3页面均可以有权限访问

下面我们通过操作SecurityConfig配置类,来做一些定制化需求实现

1、首页我都允许访问,但是level1、level2、level3页面均需要获取对应的vip1,vip2,vip3权限后才可以访问,没有权限跳转定制的登录页面

在授权方法加入授权规则:

    //授权
    @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().loginPage("/toLogin");
        //这里我们也可以只写http.formLogin();这样他就会跳转到/login,这个页面时SprignSecurity为我们准备好的登录页面
    }

现在重启项目,发现只有首页能访问,其他页面都会自动跳转到我们自己编写的登录页面:

我们只是做了一些简单的配置工作,SpringSecurity在底层已经为我们做好了一切,框架就是这样,拿来就用,如果自己想明白原理,可以点进去源码研究一下。

接下来我们要实现指定用户能访问某些页面,就要修改身份认证的配置方法,这里的用户名密码需要从数据库查询,我们就用几组死数据代表了:

    //认证
    //密码编码 passwordEncoder
    //在SpringSecurity 5.x中  新增了很多加密方法
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //正常这些数据应该从数据库读取
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("kuangshen").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");
    }

需要注意的是我们在密码外面包裹了一层 BCryptPasswordEncoder.encod方法,这是SprignSecurity的一个密码校验,现在重启项目,在登录页面输入我们设定的账号密码,神奇的发现,页面确实进行了授权。

注销及权限控制:

想实现注销按钮,首先在首页添加一个注销按钮:

修改授权配置类,开启注销功能:

    //授权
    @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().loginPage("/toLogin");
        http.formLogin();
        //这里我们也可以只写http.formLogin();这样他就会跳转到/login,这个页面时SprignSecurity为我们准备好的登录页面
        //开启注销功能
        //防止网站攻击   csrf 防止
        // 跨站攻击(代码是配置死的)
        http.csrf().disable();
        http.logout().logoutSuccessUrl("/");
    }

下面进行权限的控制,我们想让用户登录成功之后只可以看到自己可以看到的页面,自己没有权限的页面看不到,这个需要在前端index页面做手脚即可,我们一开始已经集成了 thymeleaf整合security 的包,直接判断用户是否登陆,就可以校验出用户是否有权限。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<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 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>
                    </a>
                </div>
                <div sec:authorize="isAuthenticated()">
                    <a class="item" th:href="@{/logout}">
                        <i class="sign-out card icon"></i> 注销
                    </a>
                </div>

                <!--已登录
                <a th:href="@{/usr/toUserCenter}">
                    <i class="address card icon"></i> admin
                </a>
                -->
            </div>
        </div>
    </div>

    <div class="ui segment" style="text-align: center">
        <h3>Spring Security Study by DK</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>
        <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="@{/qinjiang/js/jquery-3.1.1.min.js}"></script>
<script th:src="@{/qinjiang/js/semantic.min.js}"></script>

</body>
</html>

主要是添加了 thymeleaf的空间域名,写代码的时候 会有提示,并且保证语法不报错

现在访问页面,发现首页的菜单已经很好的被控制住了,只能显示经过我们授权后的菜单链接。

以上代码均来自于狂神,bilibili链接:https://space.bilibili.com/95256449,大家可以去网站找到对应的教学视频。再一次感谢狂神。

猜你喜欢

转载自www.cnblogs.com/dk1024/p/12917305.html
今日推荐