springboot綜合案例第三課

SpringSecurity入門

什么是SpringSecurity

Spring Security 的前身是 Acegi Security ,是 Spring 項目組中用來提供安全認證服務的框架。

(https://projects.spring.io/spring-security/) Spring Security 為基于J2EE企業應用軟件提供了全面安全服務。特別

是使用領先的J2EE解決方案-Spring框架開發的企業軟件項目。人們使用Spring Security有很多種原因,不過通常吸

引他們的是在J2EE Servlet規范或EJB規范中找不到典型企業應用場景的解決方案。特別要指出的是他們不能再

WAR 或 EAR 級別進行移植。這樣,如果你更換服務器環境,就要,在新的目標環境進行大量的工作,對你的應用

系統進行重新配置安全。使用Spring Security 解決了這些問題,也為你提供很多有用的,完全可以指定的其他安

全特性。安全包括兩個主要操作。

  • “認證”,是為用戶建立一個他所聲明的主體。主題一般式指用戶,設備或可以在你系統中執行動作的其他系

統。(簡單來說:系統認為用戶是否能登錄)

  • “授權”,指的是一個用戶能否在你的應用中執行某個操作,在到達授權判斷之前,身份的主題已經由身份驗證

過程建立了。(簡單來說:系統判斷用戶是否有權限去做某些事情)

這些概念是通用的,不是Spring Security特有的。在身份驗證層面,Spring Security廣泛支持各種身份驗證模式,

這些驗證模型絕大多數都由第三方提供,或則正在開發的有關標準機構提供的,例如 Internet Engineering Task

Force.作為補充,Spring Security 也提供了自己的一套驗證功能。

Spring Security 目前支持認證一體化如下認證技術: HTTP BASIC authentication headers (一個基于IEFT RFC 的

標準) HTTP Digest authentication headers (一個基于IEFT RFC 的標準) HTTP X.509 client certi?cate exchange

(一個基于IEFT RFC 的標準) LDAP (一個非常常見的跨平臺認證需要做法,特別是在大環境) Form-based

authentication (提供簡單用戶接口的需求) OpenID authentication Computer Associates Siteminder JA-SIG

Central Authentication Service (CAS,這是一個流行的開源單點登錄系統) Transparent authentication context

propagation for Remote Method Invocation and HttpInvoker (一個Spring遠程調用協議)

用戶登錄認證

表結構分析與創建

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-GnUk2Dvg-1692278828416)(day03_springboot綜合案例.assets/image-20210516220645141.png)]

-- 用戶表
CREATE TABLE users(id VARCHAR(32) PRIMARY KEY,email VARCHAR(50) UNIQUE NOT NULL,username VARCHAR(50),PASSWORD VARCHAR(100),phoneNum VARCHAR(20),STATUS INT
);-- 角色表
CREATE TABLE role(id VARCHAR(32) PRIMARY KEY,roleName VARCHAR(50) ,roleDesc VARCHAR(50)
);-- 用戶角色關聯表
CREATE TABLE users_role(userId VARCHAR(32),roleId VARCHAR(32),PRIMARY KEY(userId,roleId),FOREIGN KEY (userId) REFERENCES users(id),FOREIGN KEY (roleId) REFERENCES role(id)
);-- 資源權限表
CREATE TABLE permission(id VARCHAR(32)  PRIMARY KEY,permissionName VARCHAR(50) ,url VARCHAR(50)
);-- 角色權限關聯表
CREATE TABLE role_permission(permissionId VARCHAR(32),roleId VARCHAR(32),PRIMARY KEY(permissionId,roleId),FOREIGN KEY (permissionId) REFERENCES permission(id),FOREIGN KEY (roleId) REFERENCES role(id)
);

創建類

創建UserInfo


@Data
public class UserInfo {private String id;private String username;private String email;private String password;private String phoneNum;private int status;private String statusStr;private List<Role> roles;
}

創建Role


@Data
public class Role {private String id;private String roleName;private String roleDesc;private List<Permission> permissions;private List<UserInfo> users;
}

創建Permission


@Data
public class Permission {private String id;private String permissionName;private String url;private List<Role> roles;
}

Spring Security數據庫認證底層

在Spring Security中如果想要使用數據進行認證操作,有很多種操作方式,這里我們介紹使用UserDetails、

UserDetailsService來完成操作。

  • UserDetails

    public interface UserDetails extends Serializable {Collection<? extends GrantedAuthority> getAuthorities();String getPassword();String getUsername();boolean isAccountNonExpired();boolean isAccountNonLocked();boolean isCredentialsNonExpired();boolean isEnabled();
    }
    

    UserDatails是一個接口,我們可以認為UserDetails作用是于封裝當前進行認證的用戶信息,但由于其是一個

    接口,所以我們可以對其進行實現,也可以使用Spring Security提供的一個UserDetails的實現類User來完成

    操作,Ctrl+Alt+B 查找接口實現類

    以下是User類的部分代碼

    public class User implements UserDetails, CredentialsContainer {private String password;private final String username;private final Set<GrantedAuthority> authorities;private final boolean accountNonExpired; //帳戶是否過期private final boolean accountNonLocked; //帳戶是否鎖定private final boolean credentialsNonExpired; //認證是否過期 private final boolean enabled; //帳戶是否可用 
  • UserDetailsService

    public interface UserDetailsService {UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    }
    

    上面將UserDetails與UserDetailsService做了一個簡單的介紹,那么我們具體如何完成Spring Security的數據庫認

    證操作,我們通過用戶管理中用戶登錄來完成Spring Security的認證操作。

用戶登錄流程分析

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KG7Pu1wO-1692278828417)(assets/image-20201012180237425.png)]

登錄認證

添加依賴

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

Spring Security配置類

package cn.yanqi.config;import cn.yanqi.service.UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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 org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;// @EnableGlobalMethodSecurity(jsr250Enabled = true)   //開啟jsr250注解
// @EnableGlobalMethodSecurity(securedEnabled = true)  //開啟secured注解
// @EnableGlobalMethodSecurity(prePostEnabled = true)  //開啟表達式注解
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate UserService userService;@Overrideprotected void configure(HttpSecurity http) throws Exception {//自定義表單登錄頁面http.formLogin()//指定登錄頁面.loginPage("/to/login")//指定登錄請求.loginProcessingUrl("/login").usernameParameter("username").passwordParameter("password").successForwardUrl("/to/index").failureUrl("/to/failer").and().logout().logoutUrl("/logout").logoutSuccessUrl("/to/login").invalidateHttpSession(true) //是否清除session.and()//權限配置.authorizeRequests()//放行 登錄頁面.antMatchers("/to/login","/to/failer").permitAll()//放開 靜態資源.antMatchers("/css/**","/img/**","/js/**","/plugins/**").permitAll()//其他 資源需要登錄后訪問.anyRequest().authenticated().and()//禁用csrf.csrf().disable();//沒有權限http.exceptionHandling().accessDeniedPage("/to/403");}//認證的數據需要使用自定義的UserDetailsService@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService).passwordEncoder(passwordEncoder());}@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
}

編寫UserService

package cn.yanqi.service;import org.springframework.security.core.userdetails.UserDetailsService;
//繼承 UserDetailsService 重寫loadUserByUsername 完成認證
public interface UserService extends UserDetailsService {}

import cn.yanqi.travel.mapper.UserMapper;
import cn.yanqi.travel.pojo.Role;
import cn.yanqi.travel.pojo.UserInfo;
import cn.yanqi.travel.service.UserService;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserMapper userMapper;@Resourceprivate PasswordEncoder passwordEncoder;/*** 認證--查詢用戶* @param s* @return* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {UserInfo userInfo =  this.userMapper.findUserByUserName(s);User user = new User(userInfo.getUsername(),userInfo.getPassword(),userInfo.getStatus() == 0 ? false : true,//校驗用戶是否開啟true, //帳號是否過期 不過期true, //證號 不過期true, //帳號 不鎖定getAuthority(userInfo.getRoles()));System.out.println("用戶:"+userInfo.getUsername());System.out.println("=======================");return user;}/*** 認證--查詢用戶對應的角色*/private List<SimpleGrantedAuthority> getAuthority(List<Role> roles) {List<SimpleGrantedAuthority> list = new ArrayList<>();for(Role role : roles){System.out.println("對應角色:"+role.getRoleName());list.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));}return list;}
}    

編寫UserMapper

public interface UserMapper {/*** 通過用戶名查詢用戶* @param s* @return*/UserInfo findUserByUserName(String s);
}    

編寫UserMapper.xml

  <!--登錄認證:通過用戶名查詢用戶--><resultMap id="userresultMap" type="UserInfo" autoMapping="true"><id property="id" column="id"/><collection property="roles"   ofType="Role" javaType="List" autoMapping="true"><id property="id" column="rid"/></collection></resultMap><select id="findUserByUserName" resultMap="userresultMap">SELECT*,r.id ridFROMusers u,role r,users_role urWHEREu.id = ur.userId ANDr.id = ur.roleId ANDu.username = #{s}</select>

注意事項:如果登錄認證提交出現405,是因為通用頁面跳轉是@GetMapping, Security的登錄后臺跳轉需要post請求

把通用頁面跳轉改為@RequestMapping(“{page}”)即可

測試

登錄認證-把users表中的status狀態修改 0和1進行測試

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-64TQouaV-1692278828419)(day03_springboot綜合案例.assets/image-20210517223706124.png)]

權限控制

Spring Security配置類

// @EnableGlobalMethodSecurity(jsr250Enabled = true)   //開啟jsr250注解
// @EnableGlobalMethodSecurity(securedEnabled = true)  //開啟secured注解
// @EnableGlobalMethodSecurity(prePostEnabled = true)  //開啟表達式注解
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {//Spring Security配置類
}

代碼實現

基于方法級別權限控制,有三種方式

    /*** 查詢所有產品* @param page* @param size* @return*/// @RolesAllowed({"ADMIN","USER"}) // JSR-250注解// @RolesAllowed("ADMIN") // JSR-250注解// @Secured("ROLE_ADMIN") // Secured注解// @PreAuthorize("authentication.principal.username == 'jack'")//只有jack才可以訪問@RequestMapping("findAll")public String findAll( Model model,@RequestParam(value = "page",defaultValue = "1") Integer page,@RequestParam(value = "size",defaultValue = "5") Integer size){PageHelper.startPage(page,size);List<Product> productList =  this.productService.findAll();PageInfo pageInfo = new PageInfo(productList);model.addAttribute("pageInfo", pageInfo);return "product-list";}

uestMapping(“findAll”)
public String findAll( Model model,
@RequestParam(value = “page”,defaultValue = “1”) Integer page,
@RequestParam(value = “size”,defaultValue = “5”) Integer size){

    PageHelper.startPage(page,size);List<Product> productList =  this.productService.findAll();PageInfo pageInfo = new PageInfo(productList);model.addAttribute("pageInfo", pageInfo);return "product-list";
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40836.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40836.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40836.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

環形隊列+DMA空閑中斷+接收串口數據

環形隊列DMA空閑中斷接收串口數據 一.序言二.實驗原理三.實戰是檢驗真理的唯一標準3.1 usart1.c3.2 串口中斷 三.隊列代碼4.1 fifo.c4.2 fifo.h 五.結語 一.序言 本次實驗利用環形隊列DMA空閑中斷串口。。通過這個實驗可以非常深入的理解隊列&#xff0c;DMA,串口的知識。如果…

使用低版本vcpkg時,bootstrap-vcpkg.bat無法生成vcpkg.exe的可能原因

緣由 需要使用vcpkg中低版本的第三方庫&#xff0c;下載vcpkg后&#xff0c;回退至指定版本&#xff0c;運行bootstrap-vcpkg.bat生成vcpkg.exe時&#xff0c;命令行窗口總是一閃而過&#xff0c;但是vcpkg.exe卻沒有生成。 添加pause&#xff0c;查看錯誤 編輯bootstrap-vc…

docker的網絡模式

docker0網絡 docker容器的 虛擬網關loopback &#xff1a;回環網卡、TCP/IP網卡是否生效virtual bridge&#xff1a;linux 自身繼承了一個虛擬化功能&#xff08;kvm架構&#xff09;&#xff0c;是原生架構的一個虛擬化平臺&#xff0c;安裝了一個虛擬化平臺之后就會系統就會自…

ftp設置空閑連接超時時間和數據連接超時時間

在FTP協議中&#xff0c;可以通過配置服務器端的空閑連接超時時間來設置連接的過期時間。具體步驟如下&#xff1a; 登錄FTP服務器&#xff0c;進入服務器的配置文件目錄。通常配置文件位于/etc或/etc/vsftpd目錄下。打開FTP服務器的配置文件&#xff0c;例如vsftpd.conf。在配…

區間預測 | MATLAB實現QRBiLSTM雙向長短期記憶神經網絡分位數回歸時間序列區間預測

區間預測 | MATLAB實現QRBiLSTM雙向長短期記憶神經網絡分位數回歸時間序列區間預測 目錄 區間預測 | MATLAB實現QRBiLSTM雙向長短期記憶神經網絡分位數回歸時間序列區間預測效果一覽基本介紹模型描述程序設計參考資料 效果一覽 基本介紹 區間預測 | MATLAB實現QRBiLSTM雙向長短…

Codeforces 461B 樹形 DP

題意 傳送門 Codeforces 461B Appleman and Tree 題解 d p v , k dp_{v,k} dpv,k? 代表以節點 v v v 為根的子樹中&#xff0c;包含了 v v v 的聯通分量是否存在一個黑色節點 &#xff0c;同時其余聯通分量僅包含一個黑色節點情況下&#xff0c;劃分方案的數量。DFS 求解&…

微服務觀測性提升專項梳理

文章目錄 項目背景&#xff1a;項目目標&#xff1a;專項人員關鍵問題及風險APM 進展 項目背景&#xff1a; 隨著微服務架構的普及&#xff0c;構建和管理大規模的分布式系統變得越來越復雜。為了確保這些系統的可靠性和性能&#xff0c;以及快速排除故障&#xff0c;對微服務…

Git 合并分支時允許合并不相關的歷史

git fetch git fetch 是 Git 的一個命令&#xff0c;用于從遠程倉庫中獲取最新的提交和數據&#xff0c;同時更新本地倉庫的遠程分支指針。 使用 git fetch 命令可以獲取遠程倉庫的最新提交&#xff0c;但并不會自動合并或修改本地分支。它會將遠程倉庫的提交和引用&#xff…

Linux如何查看文件進程占用-lsof

lsof命令是什么&#xff1f; 可以列出被進程所打開的文件的信息。被打開的文件可以是 1.普通的文件&#xff0c;2.目錄 3.網絡文件系統的文件&#xff0c;4.字符設備文件 5.(函數)共享庫 6.管道&#xff0c;命名管道 7.符號鏈接 8.底層的socket字流&#xff0c;網絡socket…

Rust語法: 枚舉,泛型,trait

這是我學習Rust的筆記&#xff0c;本文適合于有一定高級語言基礎的開發者看不適合剛入門編程的人&#xff0c;對于一些概念像枚舉&#xff0c;泛型等&#xff0c;不會再做解釋&#xff0c;只寫在Rust中怎么用。 文章目錄 枚舉枚舉的定義與賦值枚舉綁定方法和函數match匹配枚舉…

代碼隨想錄算法訓練營二刷第一天| 704. 二分查找,27. 移除元素

代碼隨想錄算法訓練營二刷第一天| 704. 二分查找&#xff0c;27. 移除元素 文章目錄 代碼隨想錄算法訓練營二刷第一天| 704. 二分查找&#xff0c;27. 移除元素一、704. 二分查找二、35.搜索插入位置三、34. 在排序數組中查找元素的第一個和最后一個位置四、69.x 的平方根五、3…

【回溯】總結

1、 組合和子集問題 組合問題需要滿足一定要求才算作一個答案&#xff0c;比如數量要求&#xff08;k個數&#xff09;&#xff0c;累加和要求&#xff08;target&#xff09;。 子集問題是只要構成一個新的子集就算作一個答案。 進階&#xff1a;去重邏輯。 一般都是要對同…

Linux 5種網絡IO模型

Linux IO模型 網絡IO的本質是socket的讀取&#xff0c;socket在linux系統被抽象為流&#xff0c;IO可以理解為對流的操作。剛才說了&#xff0c;對于一次IO訪問&#xff08;以read舉例&#xff09;&#xff0c;數據會先被拷貝到操作系統內核的緩沖區中&#xff0c;然后才會從操…

LL庫實現SPI MDA發送方式驅動WS2812

1&#xff0c;首先打卡STM32CubeMX&#xff0c;配置一下工程&#xff0c;這里使用的芯片是STM32F030F4P6。 時鐘 SPI外設 SPI DMA 下載接口&#xff0c;這個不配置待會下程序后第二次就不好下載調試了。 工程配置&#xff0c;沒啥說的 選擇生成所有文件 將驅動都改為LL庫 然后直…

OpenCV之特征點匹配

特征點選取 特征點探測方法有goodFeaturesToTrack(),cornerHarris()和SURF()。一般使用goodFeaturesToTrack()就能獲得很好的特征點。goodFeaturesToTrack()定義&#xff1a; void goodFeaturesToTrack( InputArray image, OutputArray corners,int maxCorners, double qualit…

jmeter errstr :“unsupported field type for multipart.FileHeader“

在使用jmeter測試接口的時候&#xff0c;提示errstr :"unsupported field type for multipart.FileHeader"如圖所示 這是因為我們 在HTTP信息頭管理加content-type參數有問題 直接在HTTP請求中&#xff0c;勾選&#xff1a; use multipart/form-data for POST【中文…

22、touchGFX學習Model-View-Presenter設計模式

touchGFX采用MVP架構&#xff0c;如下所示&#xff1a; 本文界面如下所示&#xff1a; 本文將實現兩個操作&#xff1a; 1、觸摸屏點擊開關按鍵實現打印開關顯示信息&#xff0c;模擬開關燈效果 2、板載案按鍵控制觸摸屏LED燈的顯示和隱藏 一、觸摸屏點擊開關按鍵實現打印開…

Go語言之依賴管理

go module go module是Go1.11版本之后官方推出的版本管理工具&#xff0c;并且從Go1.13版本開始&#xff0c;go module將是Go語言默認的依賴管理工具。 GO111MODULE 要啟用go module支持首先要設置環境變量GO111MODULE 通過它可以開啟或關閉模塊支持&#xff0c;它有三個可選…

docker搭建LNMP

docker安裝 略 下載鏡像 nginx:最新版php-fpm:根據自己需求而定mysql:根據自己需求定 以下是我搭建LNMP使用的鏡像版本 rootVM-12-16-ubuntu:/docker/lnmp/php/etc# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mysql 8.0…