1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        SpringBoot整合SpringSecurity(附源碼)

        共 11709字,需瀏覽 24分鐘

         ·

        2020-10-24 05:30

        點擊上方藍色字體,選擇“標星公眾號”

        優(yōu)質文章,第一時間送達

        66套java從入門到精通實戰(zhàn)課程分享

        在前幾篇博客里,我們對于SpringBoot框架的項目中的認證還是采用最樸素的攔截器來實現(xiàn)的,那SpringBoot這么高級,就沒有什么成熟的解決方案嗎?有的,Spring Security,今天我們就來認識Spring Security,再配上一個demo加深理解。

        Spring Security簡介

        Spring Security 是針對Spring項目的安全框架,也是Spring Boot底層安全模塊默認的技術選型,他可以實現(xiàn)強大的Web安全控制,對于安全控制,我們僅需要引入?spring-boot-starter-security?模塊,進行少量的配置,即可實現(xiàn)強大的安全管理。

        記住常用的幾個類:

        • WebSecurityConfigurerAdapter:自定義 Security 策略

        • AuthenticationManagerBuilder:自定義認證策略

        • @EnableWebSecurity:開啟 WebSecurity 模式

        Spring Security的兩個主要目標是 “認證” 和 “授權”(訪問控制)。

        “認證”(Authentication)

        身份驗證是關于驗證您的憑據(jù),如用戶名/用戶ID和密碼,以驗證您的身份。

        身份驗證通常通過用戶名和密碼完成,有時與身份驗證因素結合使用。

        “授權” (Authorization)

        授權發(fā)生在系統(tǒng)成功驗證您的身份后,最終會授予您訪問資源(如信息,文件,數(shù)據(jù)庫,資金,位置,幾乎任何內容)的完全權限。

        那實際上除了SpringSecurity,用的比較多的安全框架還有shiro。可以下宏觀的了解一下

        SpringSecurity和Shiro的相同點和不同點。

        • 相同點

        認證功能、授權功能、加密功能、會話管理、緩存支持、rememberMe功能

        • 不同點

        1、SpringSecurity基于Spring開發(fā),項目中如果使用Spring作為基礎,配合SpringSecurity做權限更加方便,而Shiro需要和Spring進行整合開發(fā)

        2、SpringSecurity功能比Shiro更加豐富些,例如安全防護

        3、SpringSecurity社區(qū)資源比Shiro豐富

        4、Shiro配置和使用比較簡單,SpringSecurity上手復雜

        5、Shiro依賴性低,不需要任何框架和容器,可以獨立運行,而SpringSecurity依賴于Spring容器。

        測試Demo

        前置準備

        首先創(chuàng)建一個SpringBoot項目,勾選SpringSecurity模塊

        或者創(chuàng)建項目后導入依賴


        ???org.springframework.boot
        ???spring-boot-starter-security


        為了方便前端展示,我們還導入thymeleaf依賴

        創(chuàng)建幾個前端頁面(用于后面來測試權限訪問)提取碼:o9dz

        項目結構如下圖所示

        測試主頁及跳轉(測試時先把SpringSecurity依賴注釋掉

        編寫基礎配置類

        在項目下創(chuàng)建config包,新建SecurityConfig.java

        package?com.feng.config;

        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;

        /**
        ?*?

        springsecurity-test


        ?*?


        ?*
        ?*?@author?:?Nicer_feng
        ?*?@date?:?2020-10-13?11:38
        ?**/
        @EnableWebSecurity??//開啟WebSecurity模式
        public?class?SecurityConfig?extends?WebSecurityConfigurerAdapter?{

        ?????//?授權規(guī)則
        ????@Override
        ????protected?void?configure(HttpSecurity?http)?throws?Exception?{
        ????????//?首頁所有人可以訪問
        ????????//?其他界面只有對應的角色(權限)才可以訪問
        ????????http.authorizeRequests().antMatchers("/").permitAll()
        ????????????????.antMatchers("/level1/**").hasRole("vip1")
        ????????????????.antMatchers("/level2/**").hasRole("vip2")
        ????????????????.antMatchers("/level3/**").hasRole("vip3");
        ????}
        }

        測試

        開啟后我們再測試下

        可以發(fā)現(xiàn)報了403forbidden錯誤

        There?was?an?unexpected?error?(type=Forbidden,?status=403).
        Access?Denied

        我們在配置類中添加如未登錄強制跳轉到login頁面

        這里的http.formLogin();表示開啟自動配置的登錄功能,如果無權限則跳轉到/login

        測試發(fā)現(xiàn)確實如此,如果沒有權限則強制跳轉到登錄頁面

        但需要注意的是,這個登錄頁面并不是我們自己寫的login頁面,而是SpringSecurity自帶的默認登錄頁面

        重寫認證規(guī)則

        我們可以自定義認證規(guī)則,重寫configure(AuthenticationManagerBuilder auth)方法來配置認證的規(guī)則。

        可以看到這里的認證規(guī)則常用的有這幾種,這里先用inMemoryAuthentication(內存數(shù)據(jù)庫)的來演示

        添加配置代碼

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

        /**
        ?*?

        springsecurity-test


        ?*?


        ?*
        ?*?@author?:?Nicer_feng
        ?*?@date?:?2020-10-13?11:38
        ?**/
        @EnableWebSecurity??//開啟WebSecurity模式
        public?class?SecurityConfig?extends?WebSecurityConfigurerAdapter?{

        ????@Override
        ????protected?void?configure(AuthenticationManagerBuilder?auth)?throws?Exception?{
        ????????auth.inMemoryAuthentication()
        ????????????????.withUser("feng").password("111111").roles("vip1")
        ????????????????.and()
        ????????????????.withUser("user").password("22222").roles("vip2")
        ????????????????.and()
        ????????????????.withUser("admin").password("000000")
        ????????????????.roles("vip1","vip2","vip3");
        ????}

        ????@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();
        ????}
        }

        我們添加了三個用戶,分別擁有不同的權限,重啟tomcat后測試

        可以發(fā)現(xiàn)這里報了無id映射的錯誤,之所以報這個錯是因為從前端傳過來的密碼需要進行加密,否則無法登陸,我們是用官方推薦的bcrypt加密方式

        ????@Override
        ????????protected?void?configure(AuthenticationManagerBuilder?auth)?throws?Exception?{
        ????????????auth.inMemoryAuthentication().passwordEncoder(new?BCryptPasswordEncoder())
        ????????????????????.withUser("feng").password(new?BCryptPasswordEncoder().encode("111111"))
        ????????????????????.roles("vip1")
        ????????????????????.and()
        ????????????????????.withUser("user").password(new?BCryptPasswordEncoder().encode("222222"))
        ????????????????????.roles("vip2")
        ????????????????????.and()
        ????????????????????.withUser("admin").password(new?BCryptPasswordEncoder().encode("000000"))
        ????????????????????.roles("vip1","vip2","vip3");
        ????????}

        重啟測試

        權限注銷

        在配置類中加入注銷功能

        @Override
        ????protected?void?configure(HttpSecurity?http)?throws?Exception?{
        ????????......

        ????????//開啟自動配置的注銷的功能
        ????????//?/logout?注銷請求
        ????????http.logout();
        ????}

        在index頁面添加logout注銷功能


        "right?menu">
        ????
        ????"item"?th:href="@{/login}">
        ????????"address?card?icon">?登錄
        ????
        ????
        ????"item"?th:href="@{/logout}">
        ????????"address?card?icon">?注銷
        ????


        注意這里的默認提示中的/login和/logout都是SpringSecurity自帶的默認界面

        點擊注銷后,會返回登錄界面

        如果想要注銷后仍然回到首頁,可以在logout()后添加logoutSuccessUrl

        http.logout().logoutSuccessUrl("/");

        根據(jù)權限顯示不同頁面

        上面我們設置了三個用戶,擁有不同權限,在實際業(yè)務中,那能不能讓擁有相應權限的用戶只顯示相應的界面呢?是可以做到的,我們需要利用thymeleaf 和SpringSecurity結合的功能

        首先添加對應依賴


        ???org.thymeleaf.extras
        ???thymeleaf-extras-springsecurity5
        ???3.0.4.RELEASE


        修改前端的頁面

        頭部命名空間改為

        "en"?xmlns:th="http://www.thymeleaf.org"?xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">

        網(wǎng)頁部分

        "right?menu">
        ????
        ????"!isAuthenticated()">
        ????????"item"?th:href="@{/login}">
        ????????????"address?card?icon">?登錄
        ????????
        ????


        ????
        ????"isAuthenticated()">
        ????????"item">
        ????????????"address?card?icon">
        ????????????用戶名:"principal.username">
        ????????????角色:"principal.authorities">
        ????????
        ????


        ????"isAuthenticated()">
        ????????"item"?th:href="@{/logout}">
        ????????????"address?card?icon">?注銷
        ????????
        ????



        然后我們需要給相應模塊附上相應的權限等級

        "column"?sec:authorize="hasRole('vip1')">
        ???"ui?raised?segment">
        ???????"ui">
        ???????????"content">
        ???????????????"content">Level?1
        ???????????????

        ???????????????
        "@{/level1/1}">"bullhorn?icon">?Level-1-1

        ???????????????
        "@{/level1/2}">"bullhorn?icon">?Level-1-2

        ???????????????
        "@{/level1/3}">"bullhorn?icon">?Level-1-3

        ???????????
        ???????
        ???


        "column"?sec:authorize="hasRole('vip2')">
        ???"ui?raised?segment">
        ???????"ui">
        ???????????"content">
        ???????????????"content">Level?2
        ???????????????

        ???????????????
        "@{/level2/1}">"bullhorn?icon">?Level-2-1

        ???????????????
        "@{/level2/2}">"bullhorn?icon">?Level-2-2

        ???????????????
        "@{/level2/3}">"bullhorn?icon">?Level-2-3

        ???????????
        ???????
        ???


        "column"?sec:authorize="hasRole('vip3')">
        ???"ui?raised?segment">
        ???????"ui">
        ???????????"content">
        ???????????????"content">Level?3
        ???????????????

        ???????????????
        "@{/level3/1}">"bullhorn?icon">?Level-3-1

        ???????????????
        "@{/level3/2}">"bullhorn?icon">?Level-3-2

        ???????????????
        "@{/level3/3}">"bullhorn?icon">?Level-3-3

        ???????????
        ???????
        ???


        測試

        再次啟動測試

        可以看到我們做到“千人千面”了

        rememberMe

        在實際登錄中我們肯定有記住密碼這個狀態(tài),那在SpringSecurity中如何配置?十分簡單,只需要在授權規(guī)則內加一行http.rememberMe()即可

        重啟測試下發(fā)現(xiàn)登錄頁面多了一個Remember me的選項

        打開瀏覽器的開發(fā)者工具發(fā)現(xiàn)該cookies信息保存14天

        并且如果我們點擊注銷,該cookies信息自動刪除

        定制登錄頁

        實際業(yè)務中顯然不可能使用SpringSecurity自帶的登錄界面,我們需要定制自己的登錄頁面,首先我們要在配置內的登錄頁配置后添加指定的loginpage

        前端也需要指向我們自定義的登錄請求

        ???"item"?th:href="@{/toLogin}">
        ????????????????"address?card?icon">?登錄
        ???

        在login.html配置提交請求需要改成post

        "@{/login}"?method="post">
        ???"field">
        ???????
        ???????"ui?left?icon?input">
        ???????????type="text"?placeholder="Username"?name="username">
        ???????????"user?icon">
        ???????
        ???
        ???"field">
        ???????
        ???????"ui?left?icon?input">
        ???????????type="password"?name="password">
        ???????????"lock?icon">
        ???????
        ???
        ???type="submit"?class="ui?blue?submit?button"/>


        并且login.html增加記住我的選項框

        type="checkbox"?name="remember">?記住我

        加入這個功能時,配置類需要加入

        http.rememberMe().rememberMeParameter("remember");

        運行測試

        發(fā)現(xiàn)登錄都沒問題,但是注銷的時候缺出現(xiàn)了404錯誤,別緊張,是因為它默認防止 csrf 跨站請求偽造,因為會產(chǎn)生安全問題,我們可以將請求改為 post 表單提交,或者在 Spring security 中關閉 csrf 功能。在授權配置中增加 http.csrf().disable() 即可

        再次運行即可

        彩蛋

        如果我們想用jdbc連數(shù)據(jù)庫來看認證用戶呢(用戶信息存在數(shù)據(jù)庫中)

        首先在數(shù)據(jù)庫中創(chuàng)建一個用戶信息數(shù)據(jù)庫,這里直接貼sql

        /*
        SQLyog?Ultimate?v12.09?(64?bit)
        MySQL?-?5.7.23?:?Database?-?testspringsecurity
        *********************************************************************
        */


        /*!40101?SET?NAMES?utf8?*/;

        /*!40101?SET?SQL_MODE=''*/;

        /*!40014?SET?@OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS,?UNIQUE_CHECKS=0?*/;
        /*!40014?SET?@OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS,?FOREIGN_KEY_CHECKS=0?*/;
        /*!40101?SET?@OLD_SQL_MODE=@@SQL_MODE,?SQL_MODE='NO_AUTO_VALUE_ON_ZERO'?*/;
        /*!40111?SET?@OLD_SQL_NOTES=@@SQL_NOTES,?SQL_NOTES=0?*/;
        CREATE?DATABASE?/*!32312?IF?NOT?EXISTS*/`testspringsecurity`?/*!40100?DEFAULT?CHARACTER?SET?utf8?*/;

        USE?`testspringsecurity`;

        /*Table?structure?for?table?`authorities`?*/

        DROP?TABLE?IF?EXISTS?`authorities`;

        CREATE?TABLE?`authorities`?(
        ??`username`?varchar(50)?NOT?NULL,
        ??`authority`?varchar(50)?NOT?NULL,
        ??UNIQUE?KEY?`ix_auth_username`?(`username`,`authority`),
        ??CONSTRAINT?`fk_authorities_users`?FOREIGN?KEY?(`username`)?REFERENCES?`users`?(`username`)
        )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8;

        /*Data?for?the?table?`authorities`?*/

        insert??into?`authorities`(`username`,`authority`)?values?('feng','ROLE_vip1');

        /*Table?structure?for?table?`users`?*/

        DROP?TABLE?IF?EXISTS?`users`;

        CREATE?TABLE?`users`?(
        ??`username`?varchar(50)?NOT?NULL,
        ??`password`?varchar(500)?NOT?NULL,
        ??`enabled`?tinyint(1)?NOT?NULL,
        ??PRIMARY?KEY?(`username`)
        )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8;

        /*Data?for?the?table?`users`?*/

        insert??into?`users`(`username`,`password`,`enabled`)?values?('feng','$2a$10$cxCFUH0.O.pWGnp9KhC0He2T9jmQx4AV3mcjWMvmqM6eSq/cHfxFG',1);

        /*!40101?SET?SQL_MODE=@OLD_SQL_MODE?*/;
        /*!40014?SET?FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS?*/;
        /*!40014?SET?UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS?*/;
        /*!40111?SET?SQL_NOTES=@OLD_SQL_NOTES?*/;


        這里插入了一條數(shù)據(jù)肯定會好奇吧,下面在解釋

        在剛才的項目中添加mysql、jdbc依賴


        ????????
        ????????????org.springframework.boot
        ????????????spring-boot-starter-jdbc
        ????????

        ????????
        ????????
        ????????????mysql
        ????????????mysql-connector-java
        ????????????runtime
        ????????


        配置類添加鏈接數(shù)據(jù)庫信息

        application.properties


        spring.thymeleaf.cache=false

        spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
        spring.datasource.url=jdbc:mysql://localhost:3306/testspringsecurity?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
        spring.datasource.username=root
        spring.datasource.password=******


        我們在配置類中注釋掉inMemoryAuthentication的方法

        使用jdbcAuthentication認證,改為

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

        /**
        ?*?

        springsecurity-test


        ?*?


        ?*
        ?*?@author?:?Nicer_feng
        ?*?@date?:?2020-10-13?11:38
        ?**/
        @EnableWebSecurity??//開啟WebSecurity模式
        public?class?SecurityConfig?extends?WebSecurityConfigurerAdapter?{

        ????@Autowired
        ????private?DataSource?dataSource;

        ????@Override
        ????protected?void?configure(AuthenticationManagerBuilder?auth)?throws?Exception?{
        //????????auth.inMemoryAuthentication().passwordEncoder(new?BCryptPasswordEncoder())
        //????????????????.withUser("feng").password(new?BCryptPasswordEncoder().encode("111111"))
        //????????????????.roles("vip1")
        //????????????????.and()
        //????????????????.withUser("user").password(new?BCryptPasswordEncoder().encode("222222"))
        //????????????????.roles("vip2")
        //????????????????.and()
        //????????????????.withUser("admin").password(new?BCryptPasswordEncoder().encode("000000"))
        //????????????????.roles("vip1","vip2","vip3");

        ????????auth.jdbcAuthentication()
        ????????????????.dataSource(dataSource)
        ????????????????.usersByUsernameQuery("select?*?from?users?WHERE?username=?")
        ????????????????.authoritiesByUsernameQuery("select?*?from?authorities?where?username=?")
        ????????????????.passwordEncoder(new?BCryptPasswordEncoder());

        ????}

        ????@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");

        ????????http.rememberMe().rememberMeParameter("remember");

        ????????http.csrf().disable();

        ????????//開啟自動配置的注銷的功能
        ????????//?/logout?注銷請求
        ????????http.logout().logoutSuccessUrl("/");
        ????}
        }


        重啟服務器后啟動項目,上面的一串密碼就是123456通過BCrypt加密后符號,因為不加密不能認證

        注意數(shù)據(jù)庫的認證權限和用戶密碼信息分開存儲,且用戶權限前在數(shù)據(jù)庫中要加入**ROLE_**前綴

        123456通過BCrypt加密后為

        $2a$10$1gLSaAn2i4LSiq28ACalg.jOUeTNBWfSJtt19uEySy2vcUsi7qyBy

        啟動后測試(并在數(shù)據(jù)庫中添加賬戶測試登錄)



        版權聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接和本聲明。

        本文鏈接:

        https://blog.csdn.net/weixin_43876186/article/details/109054037




        粉絲福利:108本java從入門到大神精選電子書領取

        ???

        ?長按上方鋒哥微信二維碼?2 秒
        備注「1234」即可獲取資料以及
        可以進入java1234官方微信群



        感謝點贊支持下哈?

        瀏覽 38
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            色色艹| 成人视频无码在线观看 | 综合色吧 | 国产精品久久久久久久天堂 | 狠狠躁18三 片免费看 | 伊人大香蕉视频在线观看 | 男人操女人视频免费看 | 亚洲无码在线资源 | 天天操人人网 | 口爆人妻 |