狂神SpringSecurity学习笔记(基础)


前言

笔记整理来源于狂神视频https://www.bilibili.com/video/BV1PE411i7CV
主要包含SpringSecurity简介以及快速上手

一、为什么使用SpringSecurity

在web开发中,安全占据第一位置

我们可以通过一些简单的安全策略,例如过滤器,拦截器保证安全

安全是一个非功能性需求,做网站,后台应该在设计之初进行考虑,在我们设计之前

就应该把这些东西考虑进去,虽然我们可以通过拦截器,过滤器来完成需求,但是会有大量的原生代码,冗余

,而通过SpringSecurity,我们只需要进行简单的调用,便可实现无数复杂的功能

项目中所涉及的安全性问题

  • 功能权限
  • 访问权限
  • 菜单权限

市面上比较知名的安全的框架

  • shiro
  • SpringSecurity

这两个框架除了类不一样,名字不一样,其他地方有很多相似之处,我们此次便去了解SpringSecurity

一、关于SpringSecurity

参考文档:

https://docs.spring.io/spring-security/site/docs/5.2.0.RELEASE/reference/htmlsingle

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.

Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements

Spring security 是一个功能强大且高度可定制的身份验证和访问控制框架。它是保护基于 spring 的应用程序的事实上的标准。spring security 是一个框架,专注于为 java应用程序提供身份验证和授权。就像所有的spring项目一样,spring安全性的真正威力在于它可以很容易地扩展以满足客户需求

Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模板默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理

需要牢记的几个类

WebSecurityConfigurerAdapter: 自定义Security策略

AuthenticationManagerBuilder: 自定义认证策略

@EnableWebSecurity: 开启WebSecurity模式

“认证”(Authentication)

“授权”(Authorization)

这些概念是通用的,而不是只在Spring Security中存在

导入模板素材

在这里插入图片描述

首页index.html:
在这里插入图片描述
RouterControler跳往各个页面

package com.kuang.controller;

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

@Controller
public class RouterControler {

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

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

    //跳往等级页面
    @RequestMapping("/level1/{id}")
    public String toLevel1(@PathVariable("id") int id){
        return "views/level1/"+id;
    }

    //跳往等级页面
    @RequestMapping("/level2/{id}")
    public String toLevel2(@PathVariable("id") int id){
        return "views/level2/"+id;
    }

    //跳往等级页面
    @RequestMapping("/level3/{id}")
    public String toLevel3(@PathVariable("id") int id){
        return "views/level3/"+id;
    }
}

SecurityConfig配置SpringSecurity:

package com.kuang.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 {

    //链式编程
    //http安全策略
    //授权
    @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").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login").defaultSuccessUrl("/index");
        //开启注销功能,跳转回登录页

        http.logout().logoutSuccessUrl("/toLogin");
        http.csrf().disable();
        //开启记住密码功能
        http.rememberMe().rememberMeParameter("remember");
    }


    //认证,springboot 2.1.X可以直接使用
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常从数据库中获得
        //下面是从内存中取得
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("zs").password(new BCryptPasswordEncoder().encode("123")).roles("vip1","vip2","vip3")
                .and()
                .withUser("ls").password(new BCryptPasswordEncoder().encode("123")).roles("vip1","vip2")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123")).roles("vip1")
                ;
    }
}

配置完成进入网页,点击vip2自动跳转至登录页
在这里插入图片描述

此时输入数据进行登录,发现报错
在这里插入图片描述
这是因为我们允许通过的密码没有经过加密,不安全,被Spring Security驳回

Spring Security5.0+ 新增了很多加密办法

在这里插入图片描述
这里我们采用BCryptPasswordEncoder方式的加密

    //认证,springboot 2.1.X可以直接使用
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常从数据库中获得
        //下面是从内存中取得
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("zs").password(new BCryptPasswordEncoder().encode("123")).roles("vip1","vip2","vip3")
                .and()
                .withUser("ls").password(new BCryptPasswordEncoder().encode("123")).roles("vip1","vip2")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123")).roles("vip1")
                ;
    }

进行登录跳转:
在这里插入图片描述
跳转成功
那么接下来,如果我们以游客guest身份登录,登录之后只想让他看到页面的部分功能应该怎么办呢?这个时候需要通过Thymeleaf加SpringSecurity来实现

导入入Thymeleaf加SpringSecurity整合包:
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 -->
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    <version>3.0.4.RELEASE</version>
</dependency>

在页面引入命名空间:

xmlns:th="http://www.thymeleaf.org" xmlns:sec=http://www.thymeleaf.org/extras/spring-security

在html利用sec:authorize="hasRole(‘xxx’)"对权限进行筛选

index页面代码:

<!--主容器-->
<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>
                        vip等级:<span sec:authentication="principal.authorities"></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</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>
    

我们为zs赋予的权限为vip3,zs进行登录所看到的画面
在这里插入图片描述
我们为ls赋予的权限为vip2,ls进行登录所看到的画面:
在这里插入图片描述

开启记住密码功能:

http.rememberMe();

在这里插入图片描述
点击Remember me on this computer,用zs账户登录之后关闭浏览器,再次打开发现
在这里插入图片描述
账户信息依旧存在

我们查看内存中的cookie:
在这里插入图片描述
我们发现security自动创建了remember-me的cookie对象,且有效期为14天

定制首页

**在源码中我们发现:
	 * 	/**&#064;Override
	 * 	protected void configure(HttpSecurity http) throws Exception {
	 * 		  
	 *  http.authorizeRequests().antMatchers(&quot;&quot;).hasRole(&quot;USER&quot;).and().formLogin()
	 * 				.usernameParameter(&quot;username&quot;) // default is username
	 * 				.passwordParameter(&quot;password&quot;) // default is password
	 * 				.loginPage(&quot;/authentication/login&quot;) // default is /login with an HTTP get
	 * 				.failureUrl(&quot;/authentication/login?failed&quot;) // default is /login?error
	 * 				.loginProcessingUrl(&quot;/authentication/login/process&quot;); // default is /login
	 * 				// with an HTTP
	 * 				// post
	 * 	}**

我们可以通过loginPage可以设置登录页,通过failureUrl设置失败的登录页
由此我们可以设置自己的登录页

http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login").defaultSuccessUrl("/index");

这里loginProcessingUrl()相当于一个中转站,前台界面提交表单之后跳转到这个路径进行User DetailsService的验证,如果成功, defaultSuccessUrl()如果失败,那么转向failureUrl("/error.html")


**最终样式:**

在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温文艾尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值