Spring Security注解方式權(quán)限控制過程
一、摘要
Spring Security除了可以在配置文件中配置權(quán)限校驗(yàn)規(guī)則,還可以使用注解方式控制類 中方法的調(diào)用。
例如Controller中的某個(gè)方法要求必須具有某個(gè)權(quán)限才可以訪問,此時(shí)就 可以使用Spring Security框架提供的注解方式進(jìn)行控制。
二、實(shí)現(xiàn)步驟
2.1 在配置類中添加權(quán)限注解的支持
package com.by.config; //import com.by.service.UserService; import com.by.service.UserService; import org.springframework.beans.factory.annotation.Autowired; 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.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * spring security 核心配置 */ @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true)//開啟權(quán)限注解支持 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Autowired private PasswordEncoder passwordEncoder; /** * 配置認(rèn)證信息的來源 * AuthenticationManagerBuilder認(rèn)證管理器 */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 配置認(rèn)證提供者 auth.userDetailsService(userService).passwordEncoder(passwordEncoder);//配置認(rèn)證提供者 super.configure(auth);//密碼 } /** * 配置web的安全(忽略的靜態(tài)資源) * * @param web * @throws Exception */ @Override public void configure(WebSecurity web) throws Exception { //web.ignoring().antMatchers("/pages/a.html","/pages/b.html"); //web.ignoring().antMatchers("/pages/**"); //指定login.html頁面可以匿名訪問 web.ignoring().antMatchers("/login.html"); } /** * 配置HTTP請(qǐng)求的安全(認(rèn)證、授權(quán)、退出) * HttpSecurity 用于構(gòu)建一個(gè)安全過濾器鏈 SecurityFilterChain * * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { // super.configure(http); http.formLogin() .loginPage("/login.html")// 默認(rèn)頁面 .loginProcessingUrl("/login")//請(qǐng)求 .usernameParameter("username") .passwordParameter("password") // 請(qǐng)求成功后訪問哪個(gè)路徑 .defaultSuccessUrl("/index.html",true); //權(quán)限配置 http.authorizeRequests() //.antMatchers("pages/a.html").authenticated() .antMatchers("/pages/b.html").hasAuthority("add") /** * 擁有ROLE_ADMIN可以訪問d頁面 * 注意:此處雖然寫的是ADMIN,但是框架會(huì)自動(dòng)添加前綴ROLE_ */ .antMatchers("pages/c.html").hasRole("ADMIN") // 其他資源均需要登錄后訪問 .anyRequest().authenticated(); // super.configure(http); //關(guān)閉跨站請(qǐng)求防護(hù) http.csrf().disable(); } /** * 配置加密對(duì)象 * @return */ @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
2.2 創(chuàng)建Controller類
在Controller的方法上加入注解進(jìn)行權(quán)限控制
package com.by.controller; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/hello") public class HelloController { @RequestMapping("/add") /** * 表示用戶要擁有add權(quán)限 才能訪問該方法 */ @PreAuthorize("hasAuthority('add')") public String add(){ System.out.println("add"); return "success"; } }
2.3 UserService類
package com.by.service; import com.by.pojo.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; 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.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Component public class UserService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; //模擬向數(shù)據(jù)庫中插入數(shù)據(jù) public Map<String, UserInfo> map = new HashMap<>(); public void init() { UserInfo u1 = new UserInfo(); u1.setUsername("admin"); u1.setPassword(passwordEncoder.encode("123")); UserInfo u2 = new UserInfo(); u2.setUsername("user"); u2.setPassword(passwordEncoder.encode("123")); map.put(u1.getUsername(), u1); map.put(u2.getUsername(), u2); } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { init(); System.out.println("username:" + username); //模擬從數(shù)據(jù)庫中查詢用戶 UserInfo userInfo = map.get(username); if (userInfo == null) { return null; } //模擬查詢數(shù)據(jù)庫中用戶的密碼 去掉明文標(biāo)識(shí){noop} String password = userInfo.getPassword(); List<GrantedAuthority> list = new ArrayList<>(); //授權(quán),后期需要改為查詢數(shù)據(jù)庫動(dòng)態(tài)獲得用戶擁有的權(quán)限和角色 if (username.equals("admin")) { list.add(new SimpleGrantedAuthority("add")); list.add(new SimpleGrantedAuthority("delete")); } list.add(new SimpleGrantedAuthority("ROLE_ADMIN")); User user = new User(username, password, list); return user; } public static void main(String[] args) { for (int i = 0; i < 3; i++) { String password="123456"; /** * BCryptPasswordEncoder是Spring Security * 提供的一個(gè)加密的API */ BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); String hashPassWord = bCryptPasswordEncoder.encode(password); System.out.println(hashPassWord); boolean flag = bCryptPasswordEncoder.matches("123456", hashPassWord); System.out.println(flag); } } }
三、測(cè)試
可以看出admin有add方法的訪問權(quán)限,而user則沒有add方法的訪問權(quán)限
3.1 user測(cè)試
3.2 admin 測(cè)試
四、退出登錄功能
用戶完成登錄后Spring Security框架會(huì)記錄當(dāng)前用戶認(rèn)證狀態(tài)為已認(rèn)證狀態(tài),即表示用 戶登錄成功了。
那用戶如何退出登錄呢?我們可以配置類中進(jìn)行如下 配置:
package com.by.config; //import com.by.service.UserService; import com.by.service.UserService; import org.springframework.beans.factory.annotation.Autowired; 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.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * spring security 核心配置 */ @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true)//開啟權(quán)限注解支持 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Autowired private PasswordEncoder passwordEncoder; /** * 配置認(rèn)證信息的來源 * AuthenticationManagerBuilder認(rèn)證管理器 */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 配置認(rèn)證提供者 auth.userDetailsService(userService).passwordEncoder(passwordEncoder);//配置認(rèn)證提供者 super.configure(auth);//密碼 } /** * 配置web的安全(忽略的靜態(tài)資源) * * @param web * @throws Exception */ @Override public void configure(WebSecurity web) throws Exception { //web.ignoring().antMatchers("/pages/a.html","/pages/b.html"); //web.ignoring().antMatchers("/pages/**"); //指定login.html頁面可以匿名訪問 web.ignoring().antMatchers("/login.html"); } /** * 配置HTTP請(qǐng)求的安全(認(rèn)證、授權(quán)、退出) * HttpSecurity 用于構(gòu)建一個(gè)安全過濾器鏈 SecurityFilterChain * * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { // super.configure(http); http.formLogin() .loginPage("/login.html")// 默認(rèn)頁面 .loginProcessingUrl("/login")//請(qǐng)求 .usernameParameter("username") .passwordParameter("password") // 請(qǐng)求成功后訪問哪個(gè)路徑 .defaultSuccessUrl("/index.html",true); //權(quán)限配置 http.authorizeRequests() //.antMatchers("pages/a.html").authenticated() .antMatchers("/pages/b.html").hasAuthority("add") /** * 擁有ROLE_ADMIN可以訪問d頁面 * 注意:此處雖然寫的是ADMIN,但是框架會(huì)自動(dòng)添加前綴ROLE_ */ .antMatchers("pages/c.html").hasRole("ADMIN") // 其他資源均需要登錄后訪問 .anyRequest().authenticated(); /** * 退出登錄 */ http.logout() .logoutUrl("/logout") .logoutSuccessUrl("/login.html").invalidateHttpSession(true); // super.configure(http); //關(guān)閉跨站請(qǐng)求防護(hù) http.csrf().disable(); } /** * 配置加密對(duì)象 * @return */ @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
在a.html 設(shè)置一個(gè)退出登錄的超鏈接
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 我是b.html <a href="/logout" rel="external nofollow" >退出登錄</a> </body> </html>
測(cè)試
登錄后訪問localhost:8083/pages/a.html 然后點(diǎn)擊退出登錄。
如果用戶要退出登錄,只需要請(qǐng)求/logout這個(gè)URL地址就 可以,最后頁面會(huì)跳轉(zhuǎn)到login.html頁面
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java發(fā)送kafka事務(wù)消息的實(shí)現(xiàn)方法
本文主要介紹了java發(fā)送kafka事務(wù)消息的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07SpringBoot整合Log4j2實(shí)現(xiàn)自定義日志打印失效的原因及解決
本文給大家介紹了關(guān)于SpringBoot項(xiàng)目整合Log4j2實(shí)現(xiàn)自定義日志打印失效原因及解決辦法,主要的原因是因?yàn)镾pringBoot的logback包的存在,文中通過圖文給大家了詳細(xì)解決方法,需要的朋友可以參考下2024-01-01JavaEE賬號(hào)注冊(cè)模擬網(wǎng)站郵箱激活
這篇文章主要為大家詳細(xì)介紹了JavaEE賬號(hào)注冊(cè)模擬網(wǎng)站郵箱激活,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09springboot 如何修改默認(rèn)端口及application.properties常用配置
這篇文章主要介紹了springboot 如何修改默認(rèn)端口及application.properties常用配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08