小小白学Springboot(十一)——Security安全管理


文件目录结构:
在这里插入图片描述

基本准备

基础页面

所有页面均使用的 Bootstrap

我们最后实现的效果是:
一个视频首页、先判断是否登录,没有登录的跳转至登录页面;
登录后,有两种身份:普通用户、VIP用户,每种身份有不同的权限;
登录后可显示用户名且可以退出;

在这里插入图片描述

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>首页</title>

    <link href="//cdn.staticfile.org/twitter-bootstrap/3.0.1/css/bootstrap.min.css" rel="stylesheet">
    <script type="text/javascript" src="//cdn.staticfile.org/jquery/2.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="//cdn.staticfile.org/twitter-bootstrap/3.0.1/js/bootstrap.min.js"></script>

</head>
<body>

<div class="container">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <nav class="navbar navbar-default navbar-fixed-top" role="navigation">

                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav navbar-right">
                        <li>
                            <a th:href="@{/login}">登录</a>
                        </li>
                    </ul>
                </div>

            </nav>
            <div class="alert alert-danger" style="margin-top: 65px;" th:if="${param.logout}">您已退出登录</div>
            <div class="carousel slide" id="carousel-351237">
                <ol class="carousel-indicators">
                    <li data-slide-to="0" data-target="#carousel-351237">
                    </li>
                    <li data-slide-to="1" data-target="#carousel-351237">
                    </li>
                    <li data-slide-to="2" data-target="#carousel-351237" class="active">
                    </li>
                </ol>
                <div class="carousel-inner">
                    <div class="item">
                        <img alt="" th:src="@{/login/images/mt.jpg}" />
                    </div>
                    <div class="item">
                        <img alt="" th:src="@{/login/images/xw.jpg}" />
                    </div>
                    <div class="item active">
                        <img alt="" th:src="@{/login/images/lx.jpg}" />
                    </div>
                </div> <a class="left carousel-control" href="#carousel-351237" data-slide="prev"><span class="glyphicon glyphicon-chevron-left"></span></a> <a class="right carousel-control" href="#carousel-351237" data-slide="next"><span class="glyphicon glyphicon-chevron-right"></span></a>
            </div>
        </div>
    </div>
    <div class="row clearfix">
        <div class="col-md-6 column">
            <h3>
                向往的生活 第五季
            </h3>
            <p>
                《向往的生活》是由湖南卫视推出的大型生活服务纪实节目。节目记录了何炅、黄磊、张艺兴、彭昱畅、张子枫等人一起守拙归园田蘑菇屋,为观众带来一幅“自力更生,自给自足,温情待客,完美生态”的生活画面。
            </p>
            <a th:href="@{details/common/1}">点击观看</a>
        </div>
        <div class="col-md-6 column">
            <h3>
                明星大侦探之名侦探学院 第二季
            </h3>
            <p>
                《明星大侦探之名侦探学院 第二季》为《明星大侦探》兄弟篇,节目邀请了颜值与智商兼具的学霸少年进行实景推理“剧本杀”,共度欢乐爆笑的合宿生活,上演高能脑力对决。
            </p>
            <a th:href="@{details/vip/1}">点击观看</a>
        </div>
    </div>
</div>
</body>
</html>
  • 只vip可看的视频页面(details/vip/1.html)
    在这里插入图片描述
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>vip</title>
    <link href="//cdn.staticfile.org/twitter-bootstrap/3.0.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <div class="row clearfix">
                <div class="col-md-2 column">
                    <img th:src="@{/login/images/mx.jpg}" />
                </div>
                <div class="col-md-6 column" style="    margin-left: 93px;">
                    <h3>
                        明星大侦探之名侦探学院 第二季
                    </h3>
                    <p class="lead">
                        《明星大侦探之名侦探学院 第二季》为《明星大侦探》兄弟篇,节目邀请了颜值与智商兼具的学霸少年进行实景推理“剧本杀”,共度欢乐爆笑的合宿生活,上演高能脑力对决。
                    </p>
                </div>
                <div class="col-md-4 column">
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>
  • 普通用户可看的视频页面(details/common/1.html)
    在这里插入图片描述
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>common</title>
    <link href="//cdn.staticfile.org/twitter-bootstrap/3.0.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <div class="row clearfix">
                <div class="col-md-2 column">
                    <img th:src="@{/login/images/bg.jpg}" />
                </div>
                <div class="col-md-6 column" style="margin-left: 93px;">
                    <h3>
                        向往的生活 第五季
                    </h3>
                    <p class="lead">
                        《向往的生活》是由湖南卫视推出的大型生活服务纪实节目。节目记录了何炅、黄磊、张艺兴、彭昱畅、张子枫等人一起守拙归园田蘑菇屋,为观众带来一幅“自力更生,自给自足,温情待客,完美生态”的生活画面。
                    </p>
                </div>
                <div class="col-md-4 column">
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

基础数据库

  • t_customer(用户表)
    username(用户名必须唯一)、password(密码,必须是加密后的)、valid(用户是否合法,tinyint类型)这三个字段必须存在
    在这里插入图片描述
  • t_authority(用户权限表)
    authority字段的值必须为ROLE_***
    在这里插入图片描述
  • t_customer_authority(用户权限关联表)在这里插入图片描述
/*  数据库叫 springboot */

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for t_authority
-- ----------------------------
DROP TABLE IF EXISTS `t_authority`;
CREATE TABLE `t_authority` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `authority` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_authority
-- ----------------------------
INSERT INTO `t_authority` VALUES ('1', 'ROLE_common');
INSERT INTO `t_authority` VALUES ('2', 'ROLE_vip');

-- ----------------------------
-- Table structure for t_customer
-- ----------------------------
DROP TABLE IF EXISTS `t_customer`;
CREATE TABLE `t_customer` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(200) DEFAULT NULL,
  `password` varchar(200) DEFAULT NULL,
  `valid` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_customer
-- ----------------------------
INSERT INTO `t_customer` VALUES ('1', 'shitou', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1');
INSERT INTO `t_customer` VALUES ('2', '李四', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1');
 /*  对应密码均为 123456*/

-- ----------------------------
-- Table structure for t_customer_authority
-- ----------------------------
DROP TABLE IF EXISTS `t_customer_authority`;
CREATE TABLE `t_customer_authority` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `customer_id` int(20) DEFAULT NULL,
  `authority_id` int(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_customer_authority
-- ----------------------------
INSERT INTO `t_customer_authority` VALUES ('1', '1', '1');
INSERT INTO `t_customer_authority` VALUES ('2', '2', '2');

页面访问的控制类

package com.zknu.inter.controller;

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

@Controller
public class MovieController {
    @GetMapping("/details/{type}/{path}")
    public String toMovie(@PathVariable("type") String type,@PathVariable("path") String path){
        return "details/"+type+"/"+path;
    }
    // 访问 details下不同权限的页面
}

自定义用户身份认证

身份认证就是判断你输入的用户名和密码是否正确

JDBC身份认证

JDBC认证是用数据库中的信息进行认证

添加依赖

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

连接数据库配置
和以前一样,不写了
进行身份认证(SecurityConfig)
重写 WebSecurityConfigurerAdapter 中的 configure 方法

package com.zknu.inter.config;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;

import javax.sql.DataSource;

@EnableWebSecurity  // 开启MVC Security 安全支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    	// 对密码进行编码
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        String userSQL = "select name,password,valid from t_customer where name = ?";
        
        String authoritySQL = "select c.name,a.authority from t_customer c,t_authority a,t_customer_authority ca " +
                "where ca.customer_id=c.id and ca.authority_id=a.id and c.name=?";
		// 两句SQL语句基本固定 ,必须至少返回为这些值
	
        auth.jdbcAuthentication().passwordEncoder(encoder).dataSource(dataSource)
                .usersByUsernameQuery(userSQL).authoritiesByUsernameQuery(authoritySQL);
    }

}

此时我们访问 http://localhost:8080
发现会自动跳转至 Security 自带的登录页面
在这里插入图片描述
登录成功会进去首页
登录失败会报错
在这里插入图片描述
登录成功后发现我们不论哪一种身份都可访问所有页面,所以我们接下来进行用户自定义访问控制,控制页面的访问权限

自定义用户授权管理

自定义用户访问控制

接着重写 configure 方法,两个方法的参数不一样

package com.zknu.inter.config;

import org.springframework.beans.factory.annotation.Autowired;
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;

import javax.sql.DataSource;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        String userSQL = "select name,password,valid from t_customer where name = ?";
        String authoritySQL = "select c.name,a.authority from t_customer c,t_authority a,t_customer_authority ca " +
                "where ca.customer_id=c.id and ca.authority_id=a.id and c.name=?";

        auth.jdbcAuthentication().passwordEncoder(encoder).dataSource(dataSource)
                .usersByUsernameQuery(userSQL).authoritiesByUsernameQuery(authoritySQL);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()  // 开启请求访问限制
                .antMatchers("/").permitAll()  // 允许对index页面直接访问
                .antMatchers("/login/**").permitAll() 
                //  对 /login/ 下的所有文件允许访问(页面的静态资源文件)
				.antMatchers("/details/common/**").hasAnyRole("common","vip")
				// 允许权限为 common 和 vip 的用户访问 common下的所有文件
                .antMatchers("/details/vip/**").hasRole("vip")
                // 仅允许权限为 vip 的用户访问 vip 下的所有文件
                .anyRequest().authenticated()
                /*
                 匹配已经登录认证的用户*/
                .and()  
                // 功能连接
                .formLogin();
                // 开启基于表单的用户登陆

    }
}

静态资源目录结构
在这里插入图片描述
此时我们访问 http://localhost:8080
发现并没有自动跳到登录页面,因为我们对该页面进行了放行。
任意点击一个链接,发现会跳至登录页面,因为当我们请求details下的页面时,发现我们没有登录,所以会被拦截并跳转至登录页面。我们登录shitou的账号密码。
登录成功后会跳到刚刚想要访问的页面
在这里插入图片描述
因为shitou 的权限时普通用户,因此我们访问vip页面时会报403错误(无访问权限)
在这里插入图片描述
加了权限访问之后,测试会变得很麻烦,因为很多页面会变得没有访问权限,所以之后测试的时候报错首先考虑是否有访问权限。

自定义403页面(访问权限不够时的页面)

但是这个页面时非常不美观的,所以我们可以写一个403页面作为访问权限不够时的提示页面

403.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>暂无访问权限</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container" style="margin-top: 5%">
    <div class="jumbotron">
        <p>开通会员后观看</p>
        <p><a class="btn btn-primary btn-lg" role="button">
            立即开通</a>
        </p>
    </div>
</div>

</body>
</html>

403页面访问控制器

@GetMapping("/403")
    public String authority(){
        return "403";
    }

在用户访问控制中加上

.and().exceptionHandling().accessDeniedPage("/403")

在这里插入图片描述
就可以在权限不够的时候访问至403页面了。

此时我们再用shitou 用户访问 vip 页面:
在这里插入图片描述
发现我们自定义的页面已经取代了原先那个满是提示报错的页面

自定义登录页面

但我们此时的登录页面仍为Security的默认页面,不太合适吧,所以我们自己自定义一个。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/login/css/login.css}" rel="stylesheet">
</head>
<body>
    <form class="sign" method="post" th:action="@{/login}">
        <img class="img-circle img" th:src="@{/login/images/hr.jpg}">
        <h2 th:text="#{login.tip}">请登录</h2>
        <!-- #{login.tip} 这些是之前写的国际化的内容 不要和我一样忘记了,都不知道是什么东西,笑死 -->

        <div class="alert alert-danger" th:if="${param.error}">用户名或密码错误!</div>
        <!-- ${param.error} 接收登录失败后传来的参数,在下面configure方法里 -->

        <div class="form-group">
            <input type="text" class="form-control user"  name="username" th:placeholder="#{login.username}" placeholder="用户名">
        </div>
        <div class="form-group">
            <input type="password" class="form-control user" name="password" th:placeholder="#{login.password}" placeholder="密码">
        </div>
        <button class="btn btn-primary btn-block user" type="submit" th:text="#{login.button}">登录</button>
        <p class="text-center year">
            @
            <span th:text="${currentYear}">2018</span>
            -
            <span th:text="${currentYear}+1">2019</span>
        </p>
        <a class="lang" th:href="@{/login(lang='zh_CN')}"> 中文 </a>
        <a class="lang" th:href="@{/login(lang='en_US')}"> English </a>
    </form>
</body>
</html>

继续增加 configure 方法中的内容

package com.zknu.inter.config;

import org.springframework.beans.factory.annotation.Autowired;
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;

import javax.sql.DataSource;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        String userSQL = "select name,password,valid from t_customer where name = ?";
        String authoritySQL = "select c.name,a.authority from t_customer c,t_authority a,t_customer_authority ca " +
                "where ca.customer_id=c.id and ca.authority_id=a.id and c.name=?";

        auth.jdbcAuthentication().passwordEncoder(encoder).dataSource(dataSource)
                .usersByUsernameQuery(userSQL).authoritiesByUsernameQuery(authoritySQL);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/login/**").permitAll()
                .antMatchers("/details/common/**").hasAnyRole("common","vip")
                .antMatchers("/details/vip/**").hasRole("vip")
                .anyRequest().authenticated()
                .and().formLogin()
                .and().exceptionHandling().accessDeniedPage("/403");

        		http.formLogin().
        		loginPage("/login").permitAll()
        		// 登录页面定为 login 页面,可以直接是html页面,也可以是该html的访问控制类,但上面那个403必须为控制类
                .usernameParameter("username").passwordParameter("password")
                /* 接收登录是提交的用户名和密码  必须与前端表单中对应 input的name一致*/
                .defaultSuccessUrl("/",true)
               // 默认登录成功后的页面
                .failureUrl("/login?error");
                // 登录失败后访问的页面
    }
}

解释一下这句话

.defaultSuccessUrl("/",true)

为什么加 true:
在我们上一步的测试中发现,我们首先访问 首页,任意点击一个页面后会跳转至登录页面,登录成功后会返回至我们之前访问的那个页面,如果我们不加true,默认成功后的页面会优先访问我们登录前想访问的那个页面;
加true 后会优先访问我们自己定义的访问页面。

defaultSuccessUrl与successForwardUrl
功能一样,都是设置认证成功后的跳转路径。
但是 successForwardUrl 是转发过来,在Controller中需要加一个重定向
https://blog.csdn.net/qq_34975710/article/details/110232128

运行结果
登录页面
在这里插入图片描述
登录报错
在这里插入图片描述

用户退出登录

有了登录就得有退出登录
在首页中增加注销按钮

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <meta charset="UTF-8">
    <title>首页</title>

    <link href="//cdn.staticfile.org/twitter-bootstrap/3.0.1/css/bootstrap.min.css" rel="stylesheet">
    <script type="text/javascript" src="//cdn.staticfile.org/jquery/2.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="//cdn.staticfile.org/twitter-bootstrap/3.0.1/js/bootstrap.min.js"></script>

</head>
<body>

<div class="container">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <nav class="navbar navbar-default navbar-fixed-top" role="navigation">

                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav navbar-right">
                        <li>
                            <a th:href="@{/login}">登录</a>
                        </li>
                        <li>
                            <form class="logout" th:action="@{/logout}" method="post" style="padding: 5px 15px;">
                                <input type="submit" class="btn btn-warning" value="注销">
                            </form>
                        </li>
                        <!-- 必须为post方法 -->


                    </ul>
                </div>

            </nav>
            <div class="alert alert-danger" style="margin-top: 65px;" th:if="${param.logout}">您已退出登录</div>
            <div class="carousel slide" id="carousel-351237">
                <ol class="carousel-indicators">
                    <li data-slide-to="0" data-target="#carousel-351237">
                    </li>
                    <li data-slide-to="1" data-target="#carousel-351237">
                    </li>
                    <li data-slide-to="2" data-target="#carousel-351237" class="active">
                    </li>
                </ol>
                <div class="carousel-inner">
                    <div class="item">
                        <img alt="" th:src="@{/login/images/mt.jpg}" />
                    </div>
                    <div class="item">
                        <img alt="" th:src="@{/login/images/xw.jpg}" />
                    </div>
                    <div class="item active">
                        <img alt="" th:src="@{/login/images/lx.jpg}" />
                    </div>
                </div> <a class="left carousel-control" href="#carousel-351237" data-slide="prev"><span class="glyphicon glyphicon-chevron-left"></span></a> <a class="right carousel-control" href="#carousel-351237" data-slide="next"><span class="glyphicon glyphicon-chevron-right"></span></a>
            </div>
        </div>
    </div>
    <div class="row clearfix">
        <div class="col-md-6 column">
            <h3>
                向往的生活 第五季
            </h3>
            <p>
                《向往的生活》是由湖南卫视推出的大型生活服务纪实节目。节目记录了何炅、黄磊、张艺兴、彭昱畅、张子枫等人一起守拙归园田蘑菇屋,为观众带来一幅“自力更生,自给自足,温情待客,完美生态”的生活画面。
            </p>
            <a th:href="@{details/common/1}">点击观看</a>
        </div>
        <div class="col-md-6 column">
            <h3>
                明星大侦探之名侦探学院 第二季
            </h3>
            <p>
                《明星大侦探之名侦探学院 第二季》为《明星大侦探》兄弟篇,节目邀请了颜值与智商兼具的学霸少年进行实景推理“剧本杀”,共度欢乐爆笑的合宿生活,上演高能脑力对决。
            </p>
            <a th:href="@{details/vip/1}">点击观看</a>
        </div>
    </div>
</div>
</body>
</html>

接着增加configure方法

				http.logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/?logout=true");

在这里插入图片描述
测试结果
在这里插入图片描述
在这里插入图片描述

获取登录用户信息

使用SecurityContextHolder获取

在控制类中增加

package com.zknu.inter.controller;


import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MovieController {
    @GetMapping("/details/{type}/{path}")
    public String toMovie(@PathVariable("type") String type,@PathVariable("path") String path){
        return "details/"+type+"/"+path;
    }

    @GetMapping("/403")
    public String authority(){
        return "403";
    }

    @GetMapping("/getUserName")
    @ResponseBody
    public void user(){
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        UserDetails principal = (UserDetails) authentication.getPrincipal();
        System.out.println("name:"+principal.getUsername());

    }
}

因为登录后登录信息就会保存在浏览器中,只以只要不重启或关闭浏览器,你的登录信息就会一直在,所以也提示了我们如果没有重启启动类的情况下想换用户登录,需要清空浏览器的cookie
我用的是QQ浏览器,清理cookie的方法就是
在这里插入图片描述

在这里插入图片描述
测试方法
先登录,登录后再访问http://localhost:8080/getUserName
控制台会输出当前的用户名
在这里插入图片描述

用Security的sec标签获取

增加依赖
必须加版本号

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

sec标签和thymeleaf 的th一样,都是用在前端的。
将前端中登录和注销那里变成这样
在这里插入图片描述
记得加
xmlns:sec=“http://www.thymeleaf.org/thymeleaf-extras-springsecurity5”

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <meta charset="UTF-8">
    <title>首页</title>

    <link href="//cdn.staticfile.org/twitter-bootstrap/3.0.1/css/bootstrap.min.css" rel="stylesheet">
    <script type="text/javascript" src="//cdn.staticfile.org/jquery/2.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="//cdn.staticfile.org/twitter-bootstrap/3.0.1/js/bootstrap.min.js"></script>

</head>
<body>

<div class="container">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <nav class="navbar navbar-default navbar-fixed-top" role="navigation">

                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav navbar-right">
                        <li sec:authorize="isAuthenticated()">
                            <a sec:authentication="name"></a>

                        </li>
                        <li sec:authorize="isAuthenticated()">
                            <form class="logout" th:action="@{/logout}" method="post" style="padding: 5px 15px;">
                                <input type="submit" class="btn btn-warning" value="注销">
                            </form>
                        </li>

                        <li sec:authorize="isAnonymous()">
                            <a th:href="@{/login}">登录</a>
                        </li>
                    <!--    <li>
                            <a th:href="@{/login}">登录</a>
                        </li>
                        <li>
                            <form class="logout" th:action="@{/logout}" method="post" style="padding: 5px 15px;">
                                <input type="submit" class="btn btn-warning" value="注销">
                            </form>
                        </li>-->

                    </ul>
                </div>

            </nav>
            <div class="alert alert-danger" style="margin-top: 65px;" th:if="${param.logout}">您已退出登录</div>
            <div class="carousel slide" id="carousel-351237">
                <ol class="carousel-indicators">
                    <li data-slide-to="0" data-target="#carousel-351237">
                    </li>
                    <li data-slide-to="1" data-target="#carousel-351237">
                    </li>
                    <li data-slide-to="2" data-target="#carousel-351237" class="active">
                    </li>
                </ol>
                <div class="carousel-inner">
                    <div class="item">
                        <img alt="" th:src="@{/login/images/mt.jpg}" />
                    </div>
                    <div class="item">
                        <img alt="" th:src="@{/login/images/xw.jpg}" />
                    </div>
                    <div class="item active">
                        <img alt="" th:src="@{/login/images/lx.jpg}" />
                    </div>
                </div> <a class="left carousel-control" href="#carousel-351237" data-slide="prev"><span class="glyphicon glyphicon-chevron-left"></span></a> <a class="right carousel-control" href="#carousel-351237" data-slide="next"><span class="glyphicon glyphicon-chevron-right"></span></a>
            </div>
        </div>
    </div>
    <div class="row clearfix">
        <div class="col-md-6 column">
            <h3>
                向往的生活 第五季
            </h3>
            <p>
                《向往的生活》是由湖南卫视推出的大型生活服务纪实节目。节目记录了何炅、黄磊、张艺兴、彭昱畅、张子枫等人一起守拙归园田蘑菇屋,为观众带来一幅“自力更生,自给自足,温情待客,完美生态”的生活画面。
            </p>
            <a th:href="@{details/common/1}">点击观看</a>
        </div>
        <div class="col-md-6 column">
            <h3>
                明星大侦探之名侦探学院 第二季
            </h3>
            <p>
                《明星大侦探之名侦探学院 第二季》为《明星大侦探》兄弟篇,节目邀请了颜值与智商兼具的学霸少年进行实景推理“剧本杀”,共度欢乐爆笑的合宿生活,上演高能脑力对决。
            </p>
            <a th:href="@{details/vip/1}">点击观看</a>
        </div>
    </div>
</div>
</body>
</html>

isAuthenticated():判断用户是否已登录,已登录返回 true
isAuthenticated():判断用户是否未登录,未登录返回true
这两个方法的前缀都是 sec:authorize(注意! 是authorize,不是authority,刚开始我一直写的都是 ty 导致我运行一直不对,然后发现我自己拼错了,英语不好的悲哀啊,唉)
sec:authentication=“name” :获取当前用户的用户名

其他的看这里
https://www.cnblogs.com/jpfss/p/8669000.html

测试结果
在这里插入图片描述
访问首页,没有登录时只显示登录按钮,不显示注销按钮;
在这里插入图片描述
登陆后显示用户名和注销按钮在这里插入图片描述
注销后又只显示登录按钮

该功能有也可以用上面那个SecurityContextHolder完成
注意,th:if 没有 else,用th:unless替代

将thymeleaf用在js里面

方便页面布局啊跳转啊传参啊什么的。

我们将登录失败传的 error 加一个值 true
在这里插入图片描述
在login页面加js,在控制台打印

<script th:inline="javascript">
    var er = [[${param.error}]];
    console.log(er);

</script>

注意js一定要在html标签内,因为引用的th链接是在html标签上引用的
在这里插入图片描述

在这里插入图片描述
控制台打印,发现我们接收到的参数都是数组形式。

更多内容可参考
https://blog.csdn.net/mygzs/article/details/52667897

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Vue和SpringBoot打造假日旅社管理系统》课程,将讲解如何使用Vue和SpringBoot开发这个项目,手把手演示开发流程!附赠源码、文档、数据库脚本等全部资料,提供售后答疑。 课程简介本课程讲解的是《基于 Vue 和 SpringBoot 的假日旅社管理系统》,该系统支持民宿档案、民宿新闻、民宿预定、民宿评论这四大核心业务,适用于乡村民宿企业的民宿预定业务。系统给每个民宿档案提供一个唯一标识,对民宿预定、评论等各个环节进行快速批量的数据采集,确保游客及时掌握景区民宿的真实数据,方便游客进行民宿预定。另外系统还包括员工管理、组织机构管理、文件管理、权限管理功能,给旅社企业提供更个性化的民宿管理模式。假日旅社管理系统采用了基于角色的访问控制,角色和菜单关联,一个角色可以配置多个菜单权限;然后再将用户和角色关联,一位用户可以赋予多个角色。这样用户就可以根据角色拿到该有的菜单权限,更方便旅社企业的管理人员进行权限管控。   软件技术选型前端Vue:Vue 是构建前端界面的核心框架,本系统采用 2.6.14 版本。View UI:基于 Vue.js2.0 的组件库,本系统采用 4.7.0 版本。后端Spring Boot:构建系统核心逻辑的后端框架,本系统采用 2.7.0 版本。MyBatis / MyBatis Plus:后端连接数据库的框架,本系统采用 3.5.2 版本。数据库MySQL:本项目的主数据库,本系统采用 8.0.29 版本。Redis:本系统采用基于 Windows 版本的 Redis,用于图形验证码和用户菜单权限的临时存储,采用了 5.0.14 版本。开发环境VsCode:项目前端的开发工具,使用版本为 1.68.0。IntelliJ IDEA :项目后端的开发工具,使用版本为 2021.3.2。Jdk:Java 的开发环境,使用版本为 17.0.3.1。Maven:后端项目的打包工具,使用版本为 3.6.2。NodeJs:前端项目的开发环境,使用版本为 16.13.0。 软件架构分析基于 Vue 和 SpringBoot 的假日旅社管理系统包括了系统基础模块、民宿档案模块、民宿新闻模块、民宿预定模块、民宿评论模块这五大功能模块,其架构如下图所示。  接下来,分别对五大模块进行详细介绍。系统基础模块系统基础模块,是用于支撑假日旅社管理系统的正常运行,这个模块包括了登陆注册模块、员工部门管理、菜单权限管理等。假日旅社管理系统支持用户使用账号、密码和图形验证码登陆,操作界面如下图所示。  假日旅社管理系统支持用户使用手机号、姓名、密码和图形验证码注册,操作界面如下图所示。 用户成功进入系统后,可进入到基于 Vue 和 SpringBoot 的假日旅社管理系统的首页,首页展示了当前登陆的地址、现在的时间和用户配置的常用模块,如下图所示。 接着用户点击左侧的用户管理,即可进入用户管理模块,用户管理模块的首页如下图所示。 用户可以在这个模块对系统登陆用户的档案进行维护,包括添加新用户、删除用户、编辑用户、根据姓名/部门查询用户。用户可以进入部门管理模块,管理旅社的部门数据,如下图所示。 同理用户可以进入到菜单管理模块,对系统的菜单进行管理,菜单管理模块的操作界面如下图所示。 民宿档案模块第二个模块是民宿档案模块,民宿档案就是用来管理民宿的数据,民宿档案包括民宿的名称、面积、房号、房间类型、早餐情况、价格、备注等,以下是民宿档案模块的主界面。用户可以点击顶部的“新增”按钮,进入民宿档案添加界面,添加民宿档案数据,如下图所示。 其中房间类型为下拉框单项选择,如下图所示。还有早餐情况也是下拉单选,如下图所示。 用户可以对现有的民宿档案数据进行编辑更新,只需点击每一行民宿档案数据的“编辑”按钮,即可进入民宿档案数据的编辑界面,如下图所示。 用户也可以对不需要的民宿数据进行删除操作,用户点击删除时,系统会弹出二次确认弹框,如下图所示。  民宿新闻模块第三个模块是民宿新闻模块,民宿新闻就是用来管理民宿的新闻资讯,包含的功能如下所示。 民宿新闻包括民宿的名称、面积、房号、房间类型、早餐情况、价格、备注等,以下是民宿新闻模块的主界面,其中的图片仅供测试样例使用。用户可以点击顶部的“新增”按钮,进入民宿新闻添加界面,添加民宿新闻数据,如下图所示。 新闻描述字段采用了 ueditor 富文本编辑器,这是由百度 web 前端研发部开发的所见即所得的开源富文本编辑器,具有轻量、可定制、用户体验优秀等特点,基于 MIT 开源协议,所有源代码可自由修改和使用。 用户可以对现有的民宿新闻数据进行编辑更新,只需点击每一行民宿新闻数据的“编辑”按钮,即可进入民宿新闻数据的编辑界面,如下图所示。 民宿预定模块第四个模块是民宿预定模块,旅客可以在民宿预定模块中预定民宿,达到旅客的住宿目的,民宿预定模块包含的功能如下所示。民宿预定包括了预定民宿 ID、预定民宿名称、预定日期、下单时间、下单人 ID、下单人姓名、价格、是否付款、下单备注等字段,旅客首先进入民宿档案模块,可以看到每一行民宿数据都有一个预约按钮,如下图所示。 如用户点击 1 幢 102 民宿的预约按钮后,会弹出预约确认框,需要输入预约的日期,日期表单默认选择今日,如下图所示。 旅客需要点击“确认预约”按钮,完成预约操作,系统给与“预约成功”提示,如下图所示。 预约成功后,旅客可以从民宿预定模块中进行查询,如下图所示。 最后旅客进行付款操作,点击每一行右侧的付款按钮,如下图所示。支付完成后,系统将预定单的支付状态改为付款,预定流程结束,如下图所示。 民宿评论模块 第五个模块是民宿预定模块,旅客可以在民宿预定结束后评论民宿,以帮助更多的人了解民宿,民宿评论模块包含的功能如下所示。 民宿评论包括了民宿名称、民宿 ID、评论时间、评论内容、评论人 ID、评论人姓名等字段,旅客首先进入民宿档案模块,可以看到每一行民宿数据都有一个评论按钮,如下图所示。 旅客点击评论后,系统给与弹框反馈,如下图所示。  用户输入评论内容后,点击确认评论按钮,即可完成评论操作,如下图所示。  旅客评论后,即可在民宿评论模块中查看此评论数据,如下图所示。 也可以在民宿模块中,双击民宿数据查看评论信息,如下图所示。 项目总结本软件是基于 Vue 和 SpringBoot 的假日旅社管理系统,包含了民宿档案、民宿新闻、民宿预定、民宿评论这四个功能模块。 开发本系统的目的,就是为了帮助旅游景点的民宿企业提高民宿管理效率,降低人力成本,让旅游景点的民宿企业获得更多的经济效益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值