Spring Security注解方式權(quán)限控制過程
一、摘要
Spring Security除了可以在配置文件中配置權(quán)限校驗規(guī)則,還可以使用注解方式控制類 中方法的調(diào)用。
例如Controller中的某個方法要求必須具有某個權(quán)限才可以訪問,此時就 可以使用Spring Security框架提供的注解方式進(jìn)行控制。
二、實現(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請求的安全(認(rèn)證、授權(quán)、退出)
* HttpSecurity 用于構(gòu)建一個安全過濾器鏈 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")//請求
.usernameParameter("username")
.passwordParameter("password")
// 請求成功后訪問哪個路徑
.defaultSuccessUrl("/index.html",true);
//權(quán)限配置
http.authorizeRequests()
//.antMatchers("pages/a.html").authenticated()
.antMatchers("/pages/b.html").hasAuthority("add")
/**
* 擁有ROLE_ADMIN可以訪問d頁面
* 注意:此處雖然寫的是ADMIN,但是框架會自動添加前綴ROLE_
*/
.antMatchers("pages/c.html").hasRole("ADMIN")
// 其他資源均需要登錄后訪問
.anyRequest().authenticated();
// super.configure(http);
//關(guān)閉跨站請求防護(hù)
http.csrf().disable();
}
/**
* 配置加密對象
* @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)識{noop}
String password = userInfo.getPassword();
List<GrantedAuthority> list = new ArrayList<>();
//授權(quán),后期需要改為查詢數(shù)據(jù)庫動態(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
* 提供的一個加密的API
*/
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String hashPassWord = bCryptPasswordEncoder.encode(password);
System.out.println(hashPassWord);
boolean flag = bCryptPasswordEncoder.matches("123456", hashPassWord);
System.out.println(flag);
}
}
}三、測試
可以看出admin有add方法的訪問權(quán)限,而user則沒有add方法的訪問權(quán)限
3.1 user測試

3.2 admin 測試

四、退出登錄功能
用戶完成登錄后Spring Security框架會記錄當(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請求的安全(認(rèn)證、授權(quán)、退出)
* HttpSecurity 用于構(gòu)建一個安全過濾器鏈 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")//請求
.usernameParameter("username")
.passwordParameter("password")
// 請求成功后訪問哪個路徑
.defaultSuccessUrl("/index.html",true);
//權(quán)限配置
http.authorizeRequests()
//.antMatchers("pages/a.html").authenticated()
.antMatchers("/pages/b.html").hasAuthority("add")
/**
* 擁有ROLE_ADMIN可以訪問d頁面
* 注意:此處雖然寫的是ADMIN,但是框架會自動添加前綴ROLE_
*/
.antMatchers("pages/c.html").hasRole("ADMIN")
// 其他資源均需要登錄后訪問
.anyRequest().authenticated();
/**
* 退出登錄
*/
http.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login.html").invalidateHttpSession(true);
// super.configure(http);
//關(guān)閉跨站請求防護(hù)
http.csrf().disable();
}
/**
* 配置加密對象
* @return
*/
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}在a.html 設(shè)置一個退出登錄的超鏈接
<!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>測試
登錄后訪問localhost:8083/pages/a.html 然后點擊退出登錄。


如果用戶要退出登錄,只需要請求/logout這個URL地址就 可以,最后頁面會跳轉(zhuǎn)到login.html頁面
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java發(fā)送kafka事務(wù)消息的實現(xiàn)方法
本文主要介紹了java發(fā)送kafka事務(wù)消息的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
SpringBoot整合Log4j2實現(xiàn)自定義日志打印失效的原因及解決
本文給大家介紹了關(guān)于SpringBoot項目整合Log4j2實現(xiàn)自定義日志打印失效原因及解決辦法,主要的原因是因為SpringBoot的logback包的存在,文中通過圖文給大家了詳細(xì)解決方法,需要的朋友可以參考下2024-01-01
springboot 如何修改默認(rèn)端口及application.properties常用配置
這篇文章主要介紹了springboot 如何修改默認(rèn)端口及application.properties常用配置操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

