Spring boot之身份验证和访问控制

发布于:2025-07-06 ⋅ 阅读:(17) ⋅ 点赞:(0)

本文笔记跟随于遇见狂神说老师的视频

一.SpringSecurity(安全)

1.相关概念

在web开发中,安全第一位,有简单的方法,比如:拦截器,过滤器

也有安全框架,比如:SpringSecurity,shiro,两者很像,名字和类不一样。

都是做认证授权两个部分!

常见的权限有:功能权限,访问权限,菜单权限。以前做这些用拦截器,过滤器(大量的原生代码~)

 2.代码前期准备阶段

2.1导入静态资源

2.2导入security依赖

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

2.3创建controller层

package com.zhang.controller;

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


@Controller
public class RouterController {

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

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

    @GetMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id){

        return "views/level1/"+id;
    }

    @GetMapping("/level2/{id}")
    public String level2(@PathVariable("id") int id){

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

        return "views/level3/"+id;
    }
}

3.认证和授权实现

 创建一个配置类,用来设置用户的访问权限,以及认证用户的身份信息

package com.zhang.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;

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {
   //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //给传过来的url设置访问权限,首页所有人都可以访问,功能页只能是有权限的人可以访问
        //请求授权的规则
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");
        //没有权限自动跳到登录页面
        http.formLogin();

    }

    //认证  springboot 2.1.x可以直接使用
    //Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
    //要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
    //spring security 官方推荐的是使用bcrypt加密方式。

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //可以从内存也可以从数据库中取数据认证
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("zhangsan").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
                .and()
                .withUser("lisi").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
    }
}

4.注销功能实现

在配置类中实现注销功能

在前端index.xml主页面中增加注销按钮

经测试,注销成功后会跳转到登录页面,如果想要注销成功后跳转到主页面,需要在配置类中改进一下开启注销功能

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

如果用户没有登录时在导航栏只显示登录按钮,登录后在导航栏显示用户的登录信息和注销按钮并且如何根据用户的权限不同在菜单栏显示的功能也不同?

我们需要结合thymeleaf中的一些功能

sec:authorize=“isAuthenticated()”:是否认证登录!来显示不同的页面

导入maven依赖

 <!--security-thymeleaf整合包-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
            <version>2.1.2.RELEASE</version>
        </dependency>

导入以上依赖后,可以在thymeleaf中进行一些security的操作

修改前端index.xml主页面

导入命名空间:

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

修改导航栏,增加认证判断: 

<!--主容器-->
<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}">
                        <el-button type="success" icon="el-icon-check" circle></el-button> 登录
                    </a>
                </div>
                <!--如果已登录-->
                <div sec:authorize="isAuthenticated()">
                    <a class="item">
                        <el-button type="primary" icon="el-icon-edit" circle></el-button>
                        用户名:<span sec:authentication="principal.username"></span>
                    </a>
                </div>

                <a class="item" th:href="@{/logout}">
                    <el-button type="danger" icon="el-icon-delete" circle></el-button> 注销
                </a>

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

重启后点击注销会报404的错误,是因为它默认防止csrf跨站请求伪造,因为会产生安全问题,我们可以将请求改为post表单提交,或者在spring security中关闭csrf功能

        http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求

到此,可以在导航栏正确的显示登录前后的信息,接下来实现根据用户权限不同,在菜单栏显示不同页面。

修改前端index.xml主页面

sec:authorize=“hasRole()”,为具有相应权限的用户设置可访问的页面

5.记住我及首页定制

5.1记住我功能实现

登录之后,关闭浏览器,登录记录就没了,如果关闭浏览器再打开,还要显示登录的记录,我们需要设置一个记住我的功能。

在配置类中添加以下代码:

//实现记住我的功能
        http.rememberMe();

重启项目,登录页多了一个记住我功能,关闭浏览器后重新打开,发现登录记录还存在。

检查cookie发现,记住我被保存在cookie中,点击注销按钮后,cookie中的记住我被删除

结论:登录成功后,将cookie发送给浏览器保存,以后登录带上这个cookie,只要通过检查就可以免登录了。如果点击注销,则会删除这个cookie 。

5.2定制登录页

改变spring security默认的登录页为自定义的登录页

在刚才的登录配置功能后添加logininpage

 //没有权限自动跳到登录页面
        http.formLogin().loginPage("/tologin");

前端也要指向我们自定义的login请求

 我们登录,需要将这些信息发送到哪里,我们也需要配置,login.html 配置提交请求及方式,方式必须为post:

 <form th:action="@{/usr/tologin}" method="post">

图片实例:

 如果前端传递的参数username和password不是默认的,需要我们后台处理一下

如果username和password是以下的内容

需要在配置类中设置一下,将对应的字段进行连接

 //没有权限自动跳到登录页面
        http.formLogin().usernameParameter("/name").passwordParameter("/pwd").loginPage("/tologin");

 在登录页中增加记住我的按钮

 <div class="field">
                                <input type="checkbox" name="remeber">记住我
                            </div>
//实现记住我的功能
        http.rememberMe().rememberMeParameter("remeber");