• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 初窺SpringSecurity安全框架

    標簽: 后端  spring

    作為一名開發怎能不知道大名頂頂的安全框架呢?市面上流行的安全框架有:shiro和springSecurity。那么你經常用哪個框架做安全訪問控制呢?因為SpringBoot集成了SpringSecurity,所以我們這次來聊聊它

    概念

    Spring Security是一個能夠為基于Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,為應用系統提供聲明式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重復代碼的工作。

    SpringSecurity官網:官網

    對應依賴

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

    SpringSecurity包含的模塊:

    繼續,我們可以看到這么一幅圖,可以知道它是基于servlet過濾器實現的:

    http配置相關:

    用戶密碼驗證:

    創建項目

    1.創建新的項目,選擇thymeleaf和SpringWeb依賴
    2.新增靜態資源(代碼省略,主要是各角色頁面,需要此部分代碼可私我)
    3.添加路由控制頁面跳轉

    package com.springstudy.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";
        }
    
        // 通過restful 實現復用
        @RequestMapping("/level1/{id}")
        public String level1(@PathVariable("id") int id){
            return "views/level1/"+id;
        }
    
        @RequestMapping("/level2/{id}")
        public String level12(@PathVariable("id") int id){
            return "views/level2/"+id;
        }
    
        @RequestMapping("/level3/{id}")
        public String level3(@PathVariable("id") int id){
            return "views/level3/"+id;
        }
    }
    

    4.啟動項目查看頁面效果(默認登陸用戶名是user,登陸密碼在控制臺)

    后面我們要實現對應的權限控制效果!

    自定義登陸用戶和密碼

    老是這樣登不行啊,我么來自定義配置一下登陸用戶名和密碼

    # 清除thymeleaf緩存 這使得我們改動html代碼不用重啟項目 build一下即可生效
    spring.thymeleaf.cache=false
    # 用戶名
    spring.security.user.name=admin
    # 密碼
    spring.security.user.password=123456
    

    新增SecurityConfig配置類

    package com.springstudy.config;
    
    import org.springframework.context.annotation.Configuration;
    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;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        // 可以再這里導入userService相關配置
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 不同用戶訪問內容不同! 這里,過濾器,登錄注銷規則,安全配置,OAuth2配置
            // 我們平時只需要配置一些基本的規則即可!
    
            // 首頁是允許所有人訪問的!
            // 定制授權規則: 那些請求,哪些人可以訪問!
            http.authorizeRequests()
                    .antMatchers("/").permitAll()
                    .antMatchers("/level1/**").hasRole("guest")
                    .antMatchers("/level2/**").hasRole("vip")
                    .antMatchers("/level3/**").hasRole("svip");
    
            // 自定義登錄頁 配置后默認登陸頁將失效
            // login跳轉到登錄頁  /login?error 登錄失敗
            http.formLogin()
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .loginPage("/toLogin")
                    .loginProcessingUrl("/login"); // 登陸表單提交請求!
    
            // 如果注銷404,因為 Security 默認是防止 csrf 跨站偽請求!
            // http.csrf().disable(); // 可能會讓我們系統不安全
    
            // 注銷 開啟默認的注銷功能!
            http.logout().logoutSuccessUrl("/"); // 注銷成功后跳轉至首頁!
    
            // 自定義的登錄頁需要配置 rememberMe 的參數名,就可以綁定到我們前端的!
            // 記住我功能
            http.rememberMe().rememberMeParameter("remember");
        }
    
        // 定義用戶的認證規則 (角色,密碼....@Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // 定義user1 uer2 user3 三個用戶的角色權限
            // 這里我們一般在用戶角色表里存儲用戶的角色信息
            // 密碼沒有加密會報500錯誤,這里我們只定義了用戶的密碼加密,但是沒有定義用戶的認證規則的加密方式
            auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                    // 一個人可以擁有多個角色!
                    .withUser("user1")
                    .password(new BCryptPasswordEncoder().encode("123456"))
                    .roles("guest")
                    .and()
                    .withUser("user2")
                    .password(new BCryptPasswordEncoder().encode("123456"))
                    .roles("guest","vip")
                    .and()
                    .withUser("user3")
                    .password(new BCryptPasswordEncoder().encode("123456"))
                    .roles("guest","vip","svip");
        }
    }
    

    修改前臺配置

    <!DOCTYPE html>
    <html lang="en"
          xmlns:th="http://www.thymeleaf.org"
          xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
    
    <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="@{/test/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">
                     <!--核心類:Authentication-->
                    <!-- 如果未登錄就顯示登陸按鈕 -->
                    <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">
                            <!--<i class="address card icon"></i>-->
                            用戶名:<span sec:authentication="principal.username"></span> &nbsp;
                            角色:<span sec:authentication="principal.authorities"></span>
                        </a>
                    </div>
    
                    <div sec:authorize="isAuthenticated()">
                        <!-- 將注銷請求也改成post提交即可! -->
                        <form th:action="@{/logout}" method="post">
    <!--                        <button type="submit" class="def-log-out">注銷</button>-->
                            <a class="item" th:href="@{/logout}" style="text-decoration:underline;">
                                注銷
                            </a>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    
        <div class="ui segment" style="text-align: center">
            <h3>Spring Security Study</h3>
        </div>
    
        <div>
            <br>
            <div class="ui three column stackable grid">
    <!--            <div sec:authorize="hasRole('vip1')">-->
                    <div class="column" sec:authorize="hasRole('guest')">
                        <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 sec:authorize="hasRole('vip2')">-->
                    <div class="column" sec:authorize="hasRole('vip')">
                        <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 sec:authorize="hasRole('vip3')">-->
                    <div class="column" sec:authorize="hasRole('svip')">
                        <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="@{/test/js/jquery-3.1.1.min.js}"></script>
    <script th:src="@{/test/js/semantic.min.js}"></script>
    </body>
    </html>
    

    重啟項目驗證

    可以看到3個用戶,且不同的模塊,實現了不同的權限控制。
    注:在我們配置注銷時,可以看到springSecurity已經幫我們配置好了

    當然我們實際的處理方式是不同的角色配置不同的菜單,不會這么控制!這里只是舉例說明Security權限控制以及thymeleaf權限控制語法。Sercurity還是登陸鑒權用的多!

    登陸頁配置:記住我

    功能:用戶沒有登錄的時候,就只顯示導航欄!如果登錄了,只顯示自己權限能夠看到的東西 根據不同的權限,前端展示不同的功能!

    springSecrity 和 thymealef 結合:

    添加依賴:

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

    前端代碼:

    <input type="checkbox" name="remember"> 記住我
    

    后端代碼:

     // 自定義的登錄頁需要配置 rememberMe 的參數名,就可以綁定到我們前端的! 
     // 記住我功能 
     http.rememberMe().rememberMeParameter("remember");
    
     // 定制登陸頁
     http.formLogin()
        .usernameParameter("username") // 前端用戶名提交參數 
        .passwordParameter("password") // 前端密碼提交參數 
        .loginPage("/toLogin") // 登錄頁面 
        .loginProcessingUrl("/login"); // 登陸表單提交請求!
    

    啟動測試看用戶信息是否存在cookie,默認過期時間15天:

    可以看到對應有個remember-me的cookie,至于這個key為何是remember-me可以去看源碼,一切的配置都能去源碼中找到答案!刪除cookie后刷新頁面看看是否自動退出了!

    退出的問題

    點擊退出發現報錯了

    這是為什么呢?
    原來SpringSecurity禁止了get方式的退出,以防止 csrf 跨站偽請求!

    // 如果注銷404,因為 Security 默認是防止 csrf 跨站偽請求!
    // http.csrf().disable(); // 可能會讓我們系統不安全
    

    那我們把退出操作改成表單提交的post方式請求即可;

    修改index.html注銷代碼:

    <form th:action="@{/logout}" method="post">
        <button type="submit" class="def-log-out">注銷</button>
        <!-- <a class="item" th:href="@{/logout}" style="text-decoration:underline;">
            注銷
        </a> -->
    </form>
    

    build 后再次點擊注銷可以驗證下!

    版權聲明:本文為iME_cho原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/iME_cho/article/details/105629241

    智能推薦

    Spark Streaming處理文件(本地文件以及hdfs上面的文件)

    標題介紹文件流之前先介紹一下Dstream 下面是來自官網一段的說明,Discretized Streams或DStream是Spark Streaming提供的基本抽象。它表示連續的數據流,可以是從源接收的輸入數據流,也可以是通過轉換輸入流生成的已處理數據流。在內部,DStream由一系列連續的RDD表示,這是Spark對不可變的分布式數據集的抽象(有關更多詳細信息,請參見Spark編程指南)。...

    《痞子衡嵌入式半月刊》 第 8 期

    痞子衡嵌入式半月刊: 第 8 期 這里分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農歷年分二十四節氣,希望在每個交節之日準時發布一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回顧 :《痞子衡嵌入式半月刊: 第 7 期》 嘮兩句 今天是小滿,小滿節氣意味著進入了大幅降水的雨季。痞子...

    (C++)二叉樹的線索化 / 線索二叉樹

    好久不見,朋友們!雖然我知道沒人看我的博客,但我還是想叨逼叨一下。啊,好久沒編程了(其實也就一周沒編),但你們知道,程序員一天不編程那能叫程序員么???雖然我不是程序員哈哈哈哈哈,但還是要有基本素養嘛。 繼續寫二叉樹,給自己立一個flag,就是這幾天要寫完之前沒做完的幾道題,和二叉樹紅黑樹各種樹之類的~~雖然有這個flag,但我還是很實誠地遵從自己的內心,買了一張明天的電影票,等我回來告訴你們好不...

    Linux內存管理:分頁機制

    《Linux內存管理:內存描述之內存節點node》 《Linux內存管理:內存描述之內存區域zone》 《Linux內存管理:內存描述之內存頁面page》 《Linux內存管理:內存描述之高端內存》 《Linux內存管理:分頁機制》 《內存管理:Linux Memory Management:MMU、段、分頁、PAE、Cache、TLB》 目錄 1 分頁機制 1.1 為什么使用多級頁表來完成映射 ...

    Logtail 混合模式:使用插件處理文件日志

    作為一個服務百萬機器的日志采集 agent,Logtail 目前已經提供了包括日志切分、日志解析(完整正則、JSON、分隔符)、日志過濾在內的常見處理功能,能夠應對絕大多數場景的處理需求。但有些時候,由于應用的歷史原因或是本身業務日志的復雜性,單一功能可能無法滿足所采集日志的處理需求,比如: 日志可能不再是單一格式,有可能同時由 JSON 或者分隔符日志組成。 日志格式可能也不固定,不同的業務邏輯...

    猜你喜歡

    Q版緩沖區溢出教程-第一章讀書筆記

    Q版緩沖區溢出教程 1.3 神秘的windows系統 1.3.1 溢出舉例: 我們編譯運行之后的結果 現在我們把程序進行更改,數組的值進行一個變化,改為’abcdefgh’然后再編譯運行 程序運行沒有問題。 如果這個時候我們把程序再次加長的話,會發生什么,內容更改為’abcdefghijklmn’。 這個時候出了錯誤說內存越界。 1.3.3對溢出報錯...

    CVPR2014 Objectness BING 源碼編譯

    CVPR2014 Objectness BING 源碼編譯 轉載請注明作者和出處:http://blog.csdn.net/u011475210 操作系統:WINDOWS 10 軟件版本:VS2013+OpenCV2.4.13 編者: WordZzzz CVPR2014 Objectness BING 源碼編譯 一資源 二環境配置 一、資源 1.論文作者主頁:http://mmcheng.net/...

    HelloSpringMVC

    配置版:理解原理使用 新建Moudle,添加web支持 確定導入了SpringMVC依賴 配置web.xml,注冊DispatcherServlet 編寫SpringMVC的配置文件spring-mvc-servlet.xml 注意:官方名稱要求:[servletname]-servlet 在servlet.xml中添加處理映射器 在servlet.xml中添加處理器適配器 在servlet.xm...

    小程序設置單個頁面頭部title字體色及背景色

    小程序設置單個頁面頭部title字體色及背景色 項目里的一個頁面白底黑字顯得很突兀,想更改一下頭部配色,上圖: 查找了文檔,發現可以修改,見鏈接: https://developers.weixin.qq.com/miniprogram/dev/api/ui/navigation-bar/wx.setNavigationBarColor.html 直接在onLoad中寫就ok,(基礎庫1.4.0才...

    (2)Spring IoC的第一個例子

    使用Eclipse,開濤老師安裝了一個插件,SpringSource Tool Suite,不知道實際是干什么的,先不安裝了。 開發環境:jdk1.8,Eclipse Oxygen(新版的eclipse),spring-framework-4.3.10.RELEASE 核心包,比開濤老師的少了一個asm,貌似又跟core合并了。 還需要幾個其它的包 創建一個java project項目 新建一個文...

    精品国产乱码久久久久久蜜桃不卡