zoukankan      html  css  js  c++  java
  • SpringSecurity 笔记

    1.概要

    SpringSecurity 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。

    正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”(或者访问控制),一般来说,Web 应用的安全性包括用户认证(Authentication)用户授权(Authorization)攻击防范 三个部分,这两点也是 Spring Security 重要核心功能。

    (1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。通俗点说就是系统认为用户是否能登录

    (2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。通俗点讲就是系统判断用户是否有权限去做某些事情。

    (3)攻击防范(防止伪造身份)

      其核心就是一组过滤器链,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式。

    记住几个类:

    • WebSecurityConfigurerAdapter: 自定义Security策略

    • AuthenticationManagerBuider: 自定义认证策略

    • @EnableWebSecurity: 开启WebSecurity模式

    2.入门项目

    准备工作

    首先引入pom依赖

    <!--security-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-java8time</artifactId>
    </dependency>

    导入静态资源,可以从 https://www.kuangstudy.com/app/code 下载,springSecurity素材,github有免费的,我找不到了

    写RouteController进行页面跳转

    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 RouterController {
        @RequestMapping({"/", "/index"})
        public String index() {
            return "index";
        }
    
        @RequestMapping({"/toLogin"})
        public String toLogin() {
            return "views/login";
        }
    
        @RequestMapping({"/level1/{id}"})
        public String level1(@PathVariable("id") Integer id) {
            return "views/level1/" + id;
        }
    
        @RequestMapping({"/level2/{id}"})
        public String level2(@PathVariable("id") Integer id) {
            return "views/level2/" + id;
        }
    
        @RequestMapping({"/level3/{id}"})
        public String level3(@PathVariable("id") Integer id) {
            return "views/level3/" + id;
        }
    
    }

    页面很简单

    编写SpringSecurityConfig配制文件

    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;
    
    @EnableWebSecurity //开启WebSecurity模式
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        //授权
        //链式编程
        //重写configure配置,编写权限校验规则
        @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();
    
            //开启了注销功能
            http.logout().logoutSuccessUrl("/");
        }
    
        //认证
        //密码编码:PasswordEncoder
        //在spring Security 5.0+ 新增了很多的加密方法
        //重写configure配置,将我们自己的校验密码器注入到该bean中
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //这些数据正常应该从数据库中读
            auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                    .withUser("yangyang").password(new BCryptPasswordEncoder().encode("123")).roles("vip2", "vip3")
                    .and()
                    .withUser("root").password(new BCryptPasswordEncoder().encode("123")).roles("vip1", "vip2", "vip3")
                    .and()
                    .withUser("guest").password(new BCryptPasswordEncoder().encode("123")).roles("vip1");
        }
    }

    WebSecurityConfig类使用了@EnableWebSecurity注解 ,以启用Spring Security的Web安全支持,并提供Spring MVC集成。它还扩展了WebSecurityConfigurerAdapter,并覆盖了一些方法来设置Web安全配置的一些细节。

    密码加密使用的类是:PasswordEncoder,需要将它进行实例化,使用BCryptPasswordEncoder实例化,并放入spring容器中

    权限规则的修改类是:继承WebSecurityConfigurerAdapter,并重写里面的configure(HttpSecurity http)方法

    configure(HttpSecurity)方法定义了哪些URL路径应该被保护,哪些不应该。也就是说,设置那些路径可以直接访问,不需要认证

    如果设置密码,没有 new BCryptPasswordEncoder().encode("123"),会出现以下错误

    thymeleaf认证功能

    导入依赖:

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

    在index.html中导入命名空间

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

    我在pom依赖中引入的是5版本的,在命名空间导入的是4版本的,我导入5版本的不管用,不知道为什么

    重点:

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

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

    <!--登录注销-->
    <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="principal.username"></span>
                角色权限:<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>

    如果有vipx的权限便显示

    <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>

    如果注销404了,就是因为它默认防止csrf跨站请求伪造,因为会产生安全问题,我们可以将请求改为post表单提交,或者在spring security中关闭csrf功能;在 SecurityConfig配置中增加 http.csrf().disable();

    定制登录页面

    1.在index.html中,设置自定义的login请求,指向toLogin

    <!--如果未登录,只显示登录-->
    <div sec:authorize="!isAuthenticated()">
        <a class="item" th:href="@{/toLogin}">
            <i class="address card icon"></i> 登录
        </a>
    </div>

    2.在login.html中,添加记住我,并指向表单提交的url

    <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="pwd">
                <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>

    注意:此处的name为自定义的user,而不是username,所以要在配置文件中设置username和password

    3.后端代码

    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;
    
    @EnableWebSecurity //开启WebSecurity模式
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        //授权
        //链式编程
        //重写configure配置,编写权限校验规则
        @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")  //指定loginPage,对应index.html登录的url
                    .usernameParameter("user") //设置username的参数,对应login.html自定义的username
                    .passwordParameter("pwd")
                    .loginProcessingUrl("/login"); //登录表单提交请求
    
            //防止网站工具,默认是get请求,改为post
            //关闭csrf功能,解决登出失败的问题
            http.csrf().disable();
    
            //注销,开启了注销功能,跳到首页
            http.logout().logoutSuccessUrl("/");
    
            //开启记住我功能 cookie,默认保存两周,自定义接受前端的参数
            http.rememberMe().rememberMeParameter("remember");
    
        }
    
        //认证
        //密码编码:PasswordEncoder
        //在spring Security 5.0+ 新增了很多的加密方法
        //重写configure配置,将我们自己的校验密码器注入到该bean中
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //这些数据正常应该从数据库中读
            auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                    .withUser("yangyang").password(new BCryptPasswordEncoder().encode("123")).roles("vip2", "vip3")
                    .and()
                    .withUser("root").password(new BCryptPasswordEncoder().encode("123")).roles("vip1", "vip2", "vip3")
                    .and()
                    .withUser("guest").password(new BCryptPasswordEncoder().encode("123")).roles("vip1");
        }
    }
  • 相关阅读:
    UVA 254 Towers of Hanoi
    UVA 701 The Archeologists' Dilemma
    UVA 185 Roman Numerals
    UVA 10994 Simple Addition
    UVA 10570 Meeting with Aliens
    UVA 306 Cipher
    UVA 10160 Servicing Stations
    UVA 317 Hexagon
    UVA 10123 No Tipping
    UVA 696 How Many Knights
  • 原文地址:https://www.cnblogs.com/LEPENGYANG/p/15632458.html
Copyright © 2011-2022 走看看