SpringSecurity官網介紹:
1 Spring Security是一個功能強大且高度可定制的身份驗證和訪問控制框架。它是用於保護基於Spring的應用程序的實際標准。 2
3 Spring Security是一個框架,致力於為Java應用程序提供身份驗證和授權。與所有Spring項目一樣,Spring Security的真正強大之處在於可以輕松擴展以滿足自定義要求
看了上面的介紹,可以知道SpringSecurity的主要功能就是:身份驗證 和 權限控制
下面帶大家進一步了解SpringSecurity的使用以及實現的過程
1、構建初始SpringBoot項目
1.1創建空項目
1.1.1選擇SpringBoot項目
1.1.2項目命名
自動配置我們只選擇Spring Web,其余的依賴自己來,為了方便控制
導入依賴
1 <!--thymeleaf整合security--> 2 <dependency> 3 <groupId>org.thymeleaf.extras</groupId> 4 <artifactId>thymeleaf-extras-springsecurity4</artifactId> 5 <version>3.0.4.RELEASE</version> 6 </dependency> 7 <!--security --> 8 <dependency> 9 <groupId>org.springframework.boot</groupId> 10 <artifactId>spring-boot-starter-security</artifactId> 11 </dependency> 12 <!--thymeleaf--> 13 <dependency> 14 <groupId>org.thymeleaf</groupId> 15 <artifactId>thymeleaf-spring5</artifactId> 16 </dependency> 17 <dependency> 18 <groupId>org.thymeleaf.extras</groupId> 19 <artifactId>thymeleaf-extras-java8time</artifactId> 20 </dependency> 21 <!--以下為系統系統自動導入,無需再次導入--> 22 <dependency> 23 <groupId>org.springframework.boot</groupId> 24 <artifactId>spring-boot-starter-web</artifactId> 25 </dependency>
好啦,現在總算把一個空項目新建完成了,接下來導入靜態資源,這里我們提供一個網盤鏈接:
https://pan.baidu.com/s/1GlTmHAf2mmOuZc53Uf6jTQ
提取碼:ypxc
大家可以自取,都是一些簡單的頁面和項目所需的css,js
新建一個Controller自測一下:
1 package com.ldk.controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.web.bind.annotation.RequestMapping; 5 import org.springframework.web.bind.annotation.ResponseBody; 6 7 /** 8 * @Author: ldk 9 * @Date: 2020/5/19 21:44 10 * @Describe: 11 */ 12 @Controller 13 public class testController { 14 15 @RequestMapping("/hello") 16 @ResponseBody 17 public String hello(){ 18 return "hello SpringSecurity"; 19 } 20 }
項目總體結構如圖:
啟動項目,訪問:http://localhost:8080/hello,又看到熟悉的:
這證明這個簡單的Web項目可以跑通。
3、新建路由Controller
1 package com.ldk.Controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.web.bind.annotation.PathVariable; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 7 /** 8 * @Author: ldk 9 * @Date: 2020/5/19 12:55 10 * @Describe: 11 */ 12 @Controller 13 public class RouterController { 14 15 @RequestMapping({"/","/index"}) 16 public String index21(){ 17 return "index"; 18 } 19 @RequestMapping("/toLogin") 20 public String ind1ex(){ 21 return "views/login"; 22 } 23 24 @RequestMapping("/level1/{id}") 25 public String ind1ex1(@PathVariable("id")int id){ 26 return "views/level1/"+id; 27 } 28 @RequestMapping("/level2/{id}") 29 public String ind1ex2(@PathVariable("id")int id){ 30 return "views/level2/"+id; 31 } 32 @RequestMapping("/level3/{id}") 33 public String ind1ex3(@PathVariable("id")int id){ 34 return "views/level3/"+id; 35 } 36 37 }
4、上主菜(配置SecurityConfig)
我們都知道,無論SpringBoot或者SpringCloud與其他框架集成,都必須先導包,在創建Config類進行配置,然后加一個類似於@Enablexxx的注解,即可使用,SpringBoot集成SpringSecurity也不例外,這一步我們先創建一個空的SecurityConfig類 並集成 WebSecurityConfigurerAdapter 類,並重寫他里面的兩個方法,這里我們解釋一下:WebSecurityConfigurerAdapter 類是個適配器, 在配置的時候,需要我們自己寫個配置類去繼承他,然后編寫自己所特殊需要的配置,我們重寫一下它的 認證 和 授權 方法,來實現自己的定制化個性服務。
在SpringSecurityApplication同級目錄下新建config文件夾,並新建SecurityConfig配置類:
1 package com.ldk.config; 2 3 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 4 import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 6 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 8 /** 9 * @Author: ldk 10 * @Date: 2020/5/19 13:38 11 * @Describe: 12 */ 13 14 @EnableWebSecurity 15 public class SecurityConfig extends WebSecurityConfigurerAdapter { 16 17 //授權 18 @Override 19 protected void configure(HttpSecurity http) throws Exception { 20 } 21 22 //認證 23 @Override 24 protected void configure(AuthenticationManagerBuilder auth) throws Exception { 25 } 26 27 }
。現在訪問以下http://localhost:8080/ 順利跳轉首頁,這個時候,首頁的level1,level2,level3頁面均可以有權限訪問
下面我們通過操作SecurityConfig配置類,來做一些定制化需求實現
1、首頁我都允許訪問,但是level1、level2、level3頁面均需要獲取對應的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().loginPage("/toLogin"); //這里我們也可以只寫http.formLogin();這樣他就會跳轉到/login,這個頁面時SprignSecurity為我們准備好的登錄頁面 }
現在重啟項目,發現只有首頁能訪問,其他頁面都會自動跳轉到我們自己編寫的登錄頁面:
我們只是做了一些簡單的配置工作,SpringSecurity在底層已經為我們做好了一切,框架就是這樣,拿來就用,如果自己想明白原理,可以點進去源碼研究一下。
接下來我們要實現指定用戶能訪問某些頁面,就要修改身份認證的配置方法,這里的用戶名密碼需要從數據庫查詢,我們就用幾組死數據代表了:
//認證 //密碼編碼 passwordEncoder //在SpringSecurity 5.x中 新增了很多加密方法 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //正常這些數據應該從數據庫讀取 auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3") .and().withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3") .and() .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1"); }
需要注意的是我們在密碼外面包裹了一層 BCryptPasswordEncoder.encod方法,這是SprignSecurity的一個密碼校驗,現在重啟項目,在登錄頁面輸入我們設定的賬號密碼,神奇的發現,頁面確實進行了授權。
注銷及權限控制:
想實現注銷按鈕,首先在首頁添加一個注銷按鈕:
修改授權配置類,開啟注銷功能:
//授權 @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.formLogin(); //這里我們也可以只寫http.formLogin();這樣他就會跳轉到/login,這個頁面時SprignSecurity為我們准備好的登錄頁面 //開啟注銷功能 //防止網站攻擊 csrf 防止 // 跨站攻擊(代碼是配置死的) http.csrf().disable(); http.logout().logoutSuccessUrl("/"); }
下面進行權限的控制,我們想讓用戶登錄成功之后只可以看到自己可以看到的頁面,自己沒有權限的頁面看不到,這個需要在前端index頁面做手腳即可,我們一開始已經集成了 thymeleaf整合security 的包,直接判斷用戶是否登陸,就可以校驗出用戶是否有權限。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<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="@{/qinjiang/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">
<!--未登錄 顯示登錄按鈕-->
<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>
</a>
</div>
<div sec:authorize="isAuthenticated()">
<a class="item" th:href="@{/logout}">
<i class="sign-out card icon"></i> 注銷 </a>
</div>
<!--已登錄 <a th:href="@{/usr/toUserCenter}"> <i class="address card icon"></i> admin </a> -->
</div>
</div>
</div>
<div class="ui segment" style="text-align: center">
<h3>Spring Security Study by DK</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>
<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>
<script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}"></script>
<script th:src="@{/qinjiang/js/semantic.min.js}"></script>
</body>
</html>
主要是添加了 thymeleaf的空間域名,寫代碼的時候 會有提示,並且保證語法不報錯
現在訪問頁面,發現首頁的菜單已經很好的被控制住了,只能顯示經過我們授權后的菜單鏈接。
以上代碼均來自於狂神,bilibili鏈接:https://space.bilibili.com/95256449,大家可以去網站找到對應的教學視頻。再一次感謝狂神。