日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringSecurity授权(访问控制)

發布時間:2023/12/3 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringSecurity授权(访问控制) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、 訪問控制url匹配

在前面講解了認證中所有常用配置,主要是對httpSecurity.formLogin()進行操作。而在配置類中httphttpSecurity.authorizeRequests()主要是對url進行控制,也就是我們所說的授權(訪問控制)。httpSecurity.authorizeRequests()也支持連綴寫法,可以有很多url匹配規則和很多權限控制方法。這些內容進行各種組合就形成了Spring Security中的授權。
在所有匹配規則中取所有規則的交集。配置順序影響了之后授權效果,越是具體的應該放在前面,越是籠統的應該放到后面。

1 antMatcher()

規則如下: ? 匹配一個字符 * 匹配0個或多個字符 ** 匹配0個或多個目錄 在實際項目中經常需要放行所有靜態資源,下面演示放行js文件夾下所有腳本文件。 .antMatchers("/js/**").permitAll() 還有一種配置方式是只要是.js文件都放行 antMatchers("/**/*.js").permitAll()

2 anyRequest()

在之前認證過程中我們就已經使用過anyRequest(),表示匹配所有的請求。一般情況下此方法都會使用,設置全部內容都需要進行認證。 代碼示例: anyRequest().authenticated();

3 regexMatchers()

3.1 介紹
使用正則表達式進行匹配。和antMatchers()主要的區別就是參數,antMatchers()參數是ant表達式,regexMatchers()參數是正則表達式。
演示所有以.js結尾的文件都被放行。
.regexMatchers(".+[.]js").permitAll()
3.2 兩個參數時使用方式
無論是antMatchers()還是regexMatchers()都具有兩個參數的方法,其中第一個參數都是HttpMethod,表示請求方式,當設置了HttpMethod后表示只有設定的特定的請求方式才執行對應的權限設置。

二、 內置訪問控制方法介紹

Spring Security匹配了URL后調用了permitAll()表示不需要認證,隨意訪問。在Spring Security中提供了多種內置控制。
底層都是基于access進行實現的。

1 permitAll()

permitAll()表示所匹配的URL任何人都允許訪問。

2 authenticated()

authenticated()表示所匹配的URL都需要被認證才能訪問。

3 anonymous()

anonymous()表示可以匿名訪問匹配的URL。和permitAll()效果類似,只是設置為anonymous()的url會執行filter 鏈中

4 denyAll()

denyAll()表示所匹配的URL都不允許被訪問。
如果用戶未被認證需要認證,如果已經認證,報403

5 rememberMe()

被“remember me”的用戶允許訪問

6 fullyAuthenticated()

如果用戶不是被remember me的,才可以訪問。

三、 角色權限判斷

除了之前講解的內置權限控制。Spring Security中還支持很多其他權限控制。這些方法一般都用于用戶已經被認證后,判斷用戶是否具有特定的要求。
底層也是調用access(參數)。參數正好是我們調用的方法名。注意如果是判斷角色會給調用方法參數前面添加ROLE_,這也是為什么正常調用方法時角色不允許以ROLE_的原因。

1 hasAuthority(String)

判斷用戶是否具有特定的權限,用戶的權限是在自定義登錄邏輯中創建User對象時指定的。

在配置類中通過hasAuthority(“admin”)設置具有admin權限時才能訪問。

.antMatchers("/main1.html").hasAuthority("admin")

1.1 數據庫代碼效果演示

1.1.1 編寫mapper

根據用戶名查詢用戶權限

/*** 根據用戶名查詢用戶權限* @param username* @return*/ List<String> selectPermissionByUsername(String username); <select id="selectPermissionByUsername" parameterType="string" resultType="string">select m.permission from user u,role_user ru,role r,role_menu rm,menu m where ru.uid=u.id and u.username=#{param1} and ru.rid=r.id and rm.rid=r.id and rm.mid=m.id </select>

1.1.2 修改MyUserDetailsServiceImpl 查詢用戶對應的權限

com.bjsxt.springscuritydemo.service.impl.MyUserDetailsServiceImpl

@Service public class MyUserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userMapper.selectByUsername(username);if(user==null){throw new UsernameNotFoundException("用戶名不存在");}// 查詢用戶對應的權限List<String> listPermission = userMapper.selectPermissionByUsername(username);List<SimpleGrantedAuthority> listAuthority = new ArrayList<SimpleGrantedAuthority>();for(String permisssion : listPermission){listAuthority.add(new SimpleGrantedAuthority(permisssion));}return new org.springframework.security.core.userdetails.User(username,user.getPassword(),listAuthority);} }

1.1.3 在配置類中添加

httpSecurity.authorizeRequests()// 放行 url / 。不放行死循環.antMatchers("/").permitAll().antMatchers("/fail").permitAll().antMatchers("/bjsxt").hasAuthority("menu:sys").anyRequest().authenticated();

1.1.4 測試效果
在瀏覽器中輸入 http://localhost:8080/bjsxt 會要求進行登錄認證,認證后如果用戶具有menu:sys權限會正常控制器,如果沒有權限會報403

2 hasAnyAuthority(String …)

如果用戶具備給定權限中某一個,就允許訪問。
下面代碼中由于大小寫和用戶的權限不相同,所以用戶無權訪問/main1.html
.antMatchers("/main1.html").hasAnyAuthority(“adMin”,“admiN”)

3 hasRole(String)

如果用戶具備給定角色就允許訪問。否則出現403。
參數取值來源于自定義登錄邏輯UserDetailsService實現類中創建User對象時給User賦予的授權。
在給用戶賦予角色時角色需要以:ROLE_ 開頭,后面添加角色名稱。例如:ROLE_abc 其中abc是角色名,ROLE_是固定的字符開頭。使用hasRole()時參數也只寫abc即可。否則啟動報錯。
給用戶賦予角色:

在配置類中直接寫abc即可。

3.1 數據庫操作

3.1.1 編寫mapper
在接口中添加com.bjsxt.springscuritydemo.mapper.UserMapper

/*** 根據用戶名查詢角色名* @param username 用戶名* @return 角色集合*/ List<String> selectRoleByUsername(String username); 在mybatis/UserMapper.xml中添加 <select id="selectRoleByUsername" parameterType="string" resultType="string">select r.name from user u,role_user ru,role r where ru.uid=u.id and u.username=#{param1} and ru.rid=r.id </select>

3.1.2 修改自定義登錄邏輯
com.bjsxt.springscuritydemo.service.impl.MyUserDetailsServiceImpl

@Service public class MyUserDetailsServiceImpl implements UserDetailsService {// 如果覺得編譯錯誤鬧心,在Mapper上添加@Component即可。@Autowiredprivate UserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {System.out.println("此方法被執行");User user = userMapper.selectByUsername(username);if(user==null){throw new UsernameNotFoundException("用戶名不存在");}// 查詢用戶對應的權限List<String> listPermission = userMapper.selectPermissionByUsername(username);List<SimpleGrantedAuthority> listAuthority = new ArrayList<SimpleGrantedAuthority>();for(String permisssion : listPermission){listAuthority.add(new SimpleGrantedAuthority(permisssion));}// 查詢用戶對應的角色List<String> listRoels = userMapper.selectRoleByUsername(username);for(String role: listRoels){listAuthority.add(new SimpleGrantedAuthority("ROLE_"+role));}return new org.springframework.security.core.userdetails.User(username,user.getPassword(),listAuthority);} }

3.1.3 在配置類中添加

.antMatchers("/bjsxt").hasRole("管理員")

3.1.4 測試
發現使用張三可以進行登錄,李四訪問時403

4 hasAnyRole(String …)

如果用戶具備給定角色的任意一個,就允許被訪問

5 hasIpAddress(String)

如果請求是指定的IP就運行訪問。
可以通過request.getRemoteAddr()獲取ip地址。
需要注意的是在本機進行測試時localhost和127.0.0.1輸出的ip地址是不一樣的。

當瀏覽器中通過localhost進行訪問時控制臺打印的內容:

當瀏覽器中通過127.0.0.1訪問時控制臺打印的內容:

當瀏覽器中通過具體ip進行訪問時控制臺打印內容:

四、 自定義403處理方案

使用Spring Security時經常會看見403(無權限),默認情況下顯示的效果如下:

而在實際項目中可能都是一個異步請求,顯示上述效果對于用戶就不是特別友好了。Spring Security支持自定義權限受限。

1 新建類
新建類實現AccessDeniedHandler。

@Component public class MyAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");PrintWriter out = httpServletResponse.getWriter();out.write("{\"status\":\"error\",\"msg\":\"權限不足,請聯系管理員!\"}");out.flush();out.close();} }

1 修改配置類
配置類中重點添加異常處理器。設置訪問受限后交給哪個對象進行處理。
myAccessDeniedHandler是在配置類中進行自動注入的。

@Autowired private AccessDeniedHandler accessDeniedHandler;

在configure()方法中添加下面內容

//異常處理 httpSecutity.exceptionHandling().accessDeniedHandler(accessDeniedHandler);

五、 基于表達式的訪問控制

1 access()方法使用

之前學習的登錄用戶權限判斷實際上底層實現都是調用access(表達式)

可以通過access()實現和之前學習的權限控制完成相同的功能。
1.1 以permitAll舉例
下面兩種寫法是等效

1.2 以hasRole舉例,下面兩種寫法是等效的。

注意:

hasRole() 參數是必須不能以ROLE_開頭
access中hasRole一定要以ROLE_開頭

六、 基于注解的訪問控制

在Spring Security中提供了一些訪問控制的注解。這些注解都是默認是都不可用的,需要通過@EnableGlobalMethodSecurity進行開啟后使用。
如果設置的條件允許,程序正常執行。如果不允許會報500

這些注解可以寫到Service接口或方法上上也可以寫到Controller或Controller的方法上。通常情況下都是寫在控制器方法上的,控制接口URL是否允許被訪問。

1 @Secured

@Secured是專門用于判斷是否具有角色的。能寫在方法或類上。@Secured參數要以ROLE_開頭。

1.1 實現步驟
1.1.1 開啟注解
在啟動類(也可以在配置類等能夠掃描的類上)上添加@EnableGlobalMethodSecurity(securedEnabled = true)

@SpringBootApplication @EnableGlobalMethodSecurity(securedEnabled = true) public class MyApp {public static void main(String [] args){SpringApplication.run(MyApp.class,args);} }

1.1.2 在控制器方法上添加@Secured注解
在LoginController中方法上添加注解

@Secured("ROLE_abc") @RequestMapping("/toMain") public String toMain(){return "redirect:/main.html"; }

1.1.3 配置類
配置類中方法配置保留最基本的配置即可。

protected void configure(HttpSecurity http) throws Exception {// 表單認證httpSecurity.formLogin().loginProcessingUrl("/login") //當發現/login時認為是登錄,需要執行UserDetailsServiceImpl.successForwardUrl("/toMain") //此處是post請求.loginPage("/login.html");// url 攔截http.authorizeRequests().antMatchers("/login.html").permitAll() //login.html不需要被認證.anyRequest().authenticated();//所有的請求都必須被認證。必須登錄后才能訪問。//關閉csrf防護http.csrf().disable();}

2 @PreAuthorize/@PostAuthorize

@PreAuthorize和@PostAuthorize都是方法或類級別注解。

@PreAuthorize表示訪問方法或類在執行之前先判斷權限,大多情況下都是使用這個注解,注解的參數和access()方法參數取值相同,都是權限表達式。

@PostAuthorize表示方法或類執行結束后判斷權限,此注解很少被使用到。

注意:

必須在啟動類@EnableGlobalMethodSecurity中設置prePostEnabled = true

2.1 實現步驟
2.1.1 開啟注解
在啟動類中開啟@PreAuthorize注解。

@SpringBootApplication @EnableGlobalMethodSecurity(prePostEnabled = true) public class MyApp {public static void main(String [] args){SpringApplication.run(MyApp.class,args);} }

2.1.2 @PreAuthorize演示
在控制器方法上添加@PreAuthorize,參數可以是任何access()支持的表達式。
如果用戶沒有管理員角色,不會打印preAuthorize

@RequestMapping("/preAuthorize") @ResponseBody @PreAuthorize("hasRole('ROLE_管理員')") public String preAuthorize(){System.out.println("preAuthorize");return "preAuthorize"; }

2.1.3 @PostAuthorize演示
如果用戶沒有管理員角色也會打印PostAuthorize

@RequestMapping("/postAuthorize") @ResponseBody @PostAuthorize("hasRole('ROLE_管理員')") public String postAuthorize(){System.out.println("PostAuthorize");return "preAuthorize"; }

七、 Remember Me功能實現

Spring Security 中Remember Me為“記住我”功能,用戶只需要在登錄時添加remember-me復選框,取值為true。Spring Security會自動把用戶信息存儲到數據源中,以后就可以不登錄進行訪問。

1 添加依賴

Spring Security實現Remember Me 功能時底層實現依賴Spring-JDBC,所以需要導入Spring-JDBC。以后多使用MyBatis框架而很少直接導入spring-jdbc,所以此處導入mybatis啟動器
同時還需要添加MySQL驅動

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.1</version> </dependency> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.48</version> </dependency>

2 配置數據源

在application.yml中配置數據源。請確保數據庫中已經存在security數據庫

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/securityusername: rootpassword: 1234

3 編寫配置

新建com.bjsxt.config.RememberMeConfig類,并創建Bean對象

@Configuration public class RememberMeConfig {@Autowiredprivate DataSource dataSource;@Beanpublic PersistentTokenRepository getPersistentTokenRepository() {JdbcTokenRepositoryImpl jdbcTokenRepositoryImpl=new JdbcTokenRepositoryImpl();jdbcTokenRepositoryImpl.setDataSource(dataSource);//自動建表,第一次啟動時需要,第二次啟動時注釋掉 // jdbcTokenRepositoryImpl.setCreateTableOnStartup(true);return jdbcTokenRepositoryImpl;} }

4 修改SecurityConfig

在SecurityConfig中添加RememberMeConfig和UserDetailsService實現類對象,并自動注入。
在configure中添加下面配置內容。

httpSecurity.rememberMe().userDetailsService(userDetailsService) //登錄邏輯交給哪個對象.tokenRepository(repository); //持久層對象

5 在客戶端頁面中添加復選框

在客戶端登錄頁面中添加remember-me的復選框,只要用戶勾選了復選框下次就不需要進行登錄了。

<form action = "/login" method="post">用戶名:<input type="text" name="username"/><br/>密碼:<input type="text" name="password"/><br/><input type="checkbox" name="remember-me" value="true"/> <br/><input type="submit" value="登錄"/> </form>

6 有效時間

默認2周時間。但是可以通過設置狀態有效時間,即使項目重新啟動下次也可以正常登錄。

//remember Me http.rememberMe().tokenValiditySeconds(120)//單位:秒.tokenRepository(repository).userDetailsService(userDetailsServiceImpl);

八、 Thymeleaf中Spring Security的使用

Spring Security可以在一些視圖技術中進行控制顯示效果。例如:JSP或Thymeleaf。在非前后端分離且使用Spring Boot的項目中多使用Thymeleaf作為視圖展示技術。

Thymeleaf對Spring Security的支持都放在thymeleaf-extras-springsecurityX中。所以需要在項目中添加此jar包的依賴和thymeleaf的依賴。

<dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity5</artifactId><version>3.0.4.RELEASE</version> </dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>

在html頁面中引入thymeleaf命名空間和security命名空間

<html xmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">

1 獲取屬性

可以在html頁面中通過 sec:authentication=""獲取UsernamePasswordAuthenticationToken中所有getXXX的內容,包含父類中的getXXX的內容。
根據源碼得出下面屬性:
? name:登錄賬號名稱
? principal:登錄主體,在自定義登錄邏輯中是UserDetails
? credentials:憑證
? authorities:權限和角色
? details:實際上是WebAuthenticationDetails的實例??梢垣@取remoteAddress(客戶端ip)和sessionId(當前sessionId)

1.1 實現步驟:

1.1.1 新建demo.html
在項目resources中新建templates文件夾,在templates中新建demo.html頁面

1.1.2 編寫demo.html
在demo.html中編寫下面內容,測試獲取到的值

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"> <head><meta charset="UTF-8"><title>Title</title> </head> <body>登錄賬號:<span sec:authentication="name">123</span><br/>登錄賬號:<span sec:authentication="principal.username">456</span><br/>憑證:<span sec:authentication="credentials">456</span><br/>權限和角色:<span sec:authentication="authorities">456</span><br/>客戶端地址:<span sec:authentication="details.remoteAddress">456</span><br/>sessionId:<span sec:authentication="details.sessionId">456</span><br/> </body> </html>

1.1.3 編寫控制器
thymeleaf頁面需要控制轉發,在控制器類中編寫下面方法

@RequestMapping("/demo") public String demo(){return "demo"; }

2 權限判斷

在html頁面中可以使用sec:authorize=”表達式”進行權限控制,判斷是否顯示某些內容。表達式的內容和access(表達式)的用法相同。如果用戶具有指定的權限,則顯示對應的內容;如果表達式不成立,則不顯示對應的元素。

2.1 不同權限的用戶顯示不同的按鈕

2.1.1 設置用戶角色和權限

設定用戶具有admin,/insert,/delete權限ROLE_abc角色。

return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_abc,/insert,/delete"));

2.1.2 控制頁面顯示效果
在頁面中根據用戶權限和角色判斷頁面中顯示的內容

通過權限判斷: <button sec:authorize="hasAuthority('/insert')">新增</button> <button sec:authorize="hasAuthority('/delete')">刪除</button> <button sec:authorize="hasAuthority('/update')">修改</button> <button sec:authorize="hasAuthority('/select')">查看</button> <br/> 通過角色判斷: <button sec:authorize="hasRole('abc')">新增</button> <button sec:authorize="hasRole('abc')">刪除</button> <button sec:authorize="hasRole('abc')">修改</button> <button sec:authorize="hasRole('abc')">查看</button>

九、 退出登錄

用戶只需要向Spring Security項目中發送/logout退出請求即可。

<a href="/logout">退出登錄</a>

為了實現更好的效果,通常添加退出的配置。默認的退出url為/logout,退出成功后跳轉到/login?logout

如果不希望使用默認值,可以通過下面的方法進行修改。

httpSecurity.logout().logoutUrl("/logout").logoutSuccessUrl("/login.html");

十、 Spring Security中CSRF

從剛開始學習Spring Security時,在配置類中一直存在這樣一行代碼:httpSecurity.csrf().disable();如果沒有這行代碼導致用戶無法被認證。
這行代碼的含義是:關閉csrf防護。

1 什么是CSRF

CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack” 或者Session Riding。通過偽造用戶請求訪問受信任站點的非法請求訪問。
跨域:只要網絡協議,ip地址,端口中任何一個不相同就是跨域請求。
客戶端與服務進行交互時,由于http協議本身是無狀態協議,所以引入了cookie進行記錄客戶端身份。在cookie中會存放session id用來識別客戶端身份的。在跨域的情況下,session id可能被第三方惡意劫持,通過這個session id向服務端發起請求時,服務端會認為這個請求是合法的,可能發生很多意想不到的事情。

2 Spring Security中CSRF

從Spring Security4開始CSRF防護默認開啟。默認會攔截請求。進行CSRF處理。CSRF為了保證不是其他第三方網站訪問,要求訪問時攜帶參數名為_csrf值為token(token在服務端產生)的內容,如果token和服務端的token匹配成功,則正常訪問。

2.1 實現步驟

2.1.1 編寫控制器方法
編寫控制器方法,跳轉到templates中login.html頁面。

@GetMapping("/showLogin") public String showLogin() {return "login"; }

2.1.2 新建login.html
在項目resources下新建templates文件夾,并在文件夾中新建login.html頁面。

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <form action = "/login" method="post"><input type="hidden" th:value="${_csrf.token}" name="_csrf" th:if="${_csrf}"/>用戶名:<input type="text" name="username"/><br/>密碼:<input type="password" name="password"/><br/><input type="submit" value="登錄"/> </form> </body> </html>

2.1.3 修改配置類
在配置類中注釋掉CSRF防護失效

//關閉csrf防護 //http.csrf().disable();

2.2 Spring Security中CSRF原理

  • 當服務器加載登錄頁面。(loginPage中的值,默認/login),先生成csrf對象,并放入作用域中,key為_csrf。之后會對${_csrf.token}進行替換,替換成服務器生成的token字符串。
  • 用戶在提交登錄表單時,會攜帶csrf的token。如果客戶端的token和服務器的token匹配說明是自己的客戶端,否則無法繼續執行。
  • 總結

    以上是生活随笔為你收集整理的SpringSecurity授权(访问控制)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。