10授權

目錄

本節大綱

一、權限管理

1. 認證

2. 授權

二、授權核心概念

三、權限管理策略

1. 基于 URL 權限管理

權限表達式

2. 基于 方法 權限管理

@EnableGlobalMethodSecurity

四、基本用法

五、原理分析

六、實戰

1. 簡介

2. 庫表設計

3. 創建 springboot 應用


本節大綱

  • 什么是權限管理
  • 權限管理核心概念
  • Spring Security 權限管理策略
  • 基于 URL 地址的權限管理
  • 基于方法的權限管理
  • 實戰

一、權限管理

1. 認證

身份認證,就是判斷一個用戶是否為合法用戶的處理過程。Spring Security 中支持多種不同方式的認證,但是無

論開發者使用那種方式認證,都不會影響授權功能使用。因為 Spring Security 很好做到了認證和授權解耦。

2. 授權

授權,即訪問控制,控制誰能訪問哪些資源。簡單的理解授權就是根據系統提前設置好的規則,給用戶分配可以

訪問某一個資源的權限,用戶根據自己所具有權限,去執行相應操作。

二、授權核心概念

在前面學習認證過程中,我們得知認證成功之后會將當前登錄用戶信息保存到 Authentication 對象中,

Authentication 對象中有一個getAuthorities() 方法,用來返回當前登錄用戶具備的權限信息,也就是當前用戶

具有權限信息。

該方法的返回值為 Collection<? extends GrantedAuthority>,

當需要進行權限判斷時,就回根據集合返回權限信息調用相應方法進行判斷。

那么問題來了,針對于這個返回值 GrantedAuthority 應該如何理解呢? 是角色還是權限?

我們針對于授權可以是基于角色權限管理和基于資源權限管理,從設計層面上來說,角色和權限是兩個完全不同

的東西:

權限是一些具體操作,角色則是某些權限集合。

如:READ_BOOK 和 ROLE_ADMIN 是完全不同的。因此至于返回值是什么取決于你的業務設計情況:

  • 基于角色權限設計就是: 用戶<=>角色<=>資源三者關系 返回就是用戶的角色
  • 基于資源權限設計就是: 用戶<=>權限<=>資源 三者關系 返回就是用戶的權限
  • 基于角色和資源權限設計就是: 用戶<=>角色<=>權限<=>資源 返回統稱為用戶的權限

為什么可以統稱為權限,因為從代碼層面角色和權限沒有太大不同都是權限,特別是在 Spring Security 中,角色

和權限處理方式基本上都是一樣的。唯一區別 SpringSecurity 在很多時候會自動給角色添加一個ROLE_前綴,而

權限則不會自動添加。

三、權限管理策略

Spring Security 中提供的權限管理策略主要有兩種類型:

  • 基于過濾器(URL)的權限管理 (FilterSecurityInterceptor)
    • 基于過濾器的權限管理主要是用來攔截 HTTP 請求,攔截下來之后,根據 HTTP 請求地址進行權限校驗。
  • 基于 AOP (方法)的權限管理 ? (MethodSecurityInterceptor)
    • 基于 AOP 權限管理主要是用來處理方法級別的權限問題。
      當需要調用某一個方法時,通過 AOP 將操作攔截下來,然后判斷用戶是否具備相關的權限。

1. 基于 URL 權限管理

  • 開發 controller
@RestController
public class DemoController {@GetMapping("/admin")public String admin() {return "admin ok";}@GetMapping("/user")public String user() {return "user ok";}@GetMapping("/getInfo")public String getInfo() {return "info ok";}
}
  • 配置授權
package com.blr.config;import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {//創建內存數據源public UserDetailsService userDetailsService() {InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").roles("ADMIN").build());inMemoryUserDetailsManager.createUser(User.withUsername("win7").password("{noop}123").roles("USER").build());inMemoryUserDetailsManager.createUser(User.withUsername("lisi").password("{noop}123").roles("READ_BOOK").build());return inMemoryUserDetailsManager;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeHttpRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasAnyRole("USER", "ADMIN").antMatchers("/getInfo").hasRole("READ_BOOK").anyRequest().authenticated().and().formLogin().and().csrf().disable();}
}
  • 啟動項目測試

權限表達式

方法

說明

hasAuthority(String authority)

當前用戶是否具備指定權限

hasAnyAuthority(String... authorities)

當前用戶是否具備指定權限中任意一個

hasRole(String role)

當前用戶是否具備指定角色

hasAnyRole(String... roles);

當前用戶是否具備指定角色中任意一個

permitAll();

放行所有請求/調用

denyAll();

拒絕所有請求/調用

isAnonymous();

當前用戶是否是一個匿名用戶

isAuthenticated();

當前用戶是否已經認證成功

isRememberMe();

當前用戶是否通過 Remember-Me 自動登錄

isFullyAuthenticated();

當前用戶是否既不是匿名用戶又不是通過 Remember-Me 自動登錄的

hasPermission(Object targetId, Object permission);

當前用戶是否具備指定目標的指定權限信息

hasPermission(Object targetId, String targetType, Object permission);

當前用戶是否具備指定目標的指定權限信息

2. 基于 方法 權限管理

基于方法的權限管理主要是通過 A0P 來實現的,Spring Security 中通過 MethodSecurityInterceptor 來提供相

關的實現。

不同在于 FilterSecurityInterceptor 只是在請求之前進行前置處理,MethodSecurityInterceptor 除了前置處理

外還可以進行后置處理。

前置處理就是在請求之前判斷是否具備相應的權限,后置處理則是對方法的執行結果進行二次過濾。前置處理和

后置處理分別對應了不同的實現類。

@EnableGlobalMethodSecurity

EnableGlobalMethodSecurity 該注解是用來開啟權限注解,用法如下:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true, jsr250Enabled=true)
public class SecurityConfig extends WebsecurityConfigurerAdapter{}
  • perPostEnabled:開啟 Spring Security 提供的四個權限注解,@PostAuthorize、@PostFilter、@PreAuthorize 以及@PreFilter。
  • securedEnabled:開啟 Spring Security 提供的 @Secured 注解支持,該注解不支持權限表達式
  • jsr250Enabled:開啟 JSR-250 提供的注解,主要是@DenyAll、@PermitAll、@RolesAll 同樣這些注解也不支持權限表達式
# 以上注解含義如下:
- @PostAuthorize: 在目前標方法執行之后進行權限校驗。
- @PostFiter: 在目標方法執行之后對方法的返回結果進行過濾。
- @PreAuthorize:在目標方法執行之前進行權限校驗。
- @PreFiter:在目前標方法執行之前對方法參數進行過濾。
- @Secured:訪問目標方法必須具各相應的角色。
- @DenyAll:拒絕所有訪問。
- @PermitAll:允許所有訪問。
- @RolesAllowed:訪問目標方法必須具備相應的角色。

這些基于方法的權限管理相關的注解,一般來說只要設置 prePostEnabled=true 就夠用了。

四、基本用法

  • 開啟注解使用
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true, jsr250Enabled=true)
public class SecurityConfig extends WebsecurityConfigurerAdapter{}
  • 使用注解
@RestController
@RequestMapping("/hello")
public class AuthorizeMethodController {@PreAuthorize("hasRole('ADMIN') and authentication.name=='root'")@GetMappingpublic String hello() {return "hello";}@PreAuthorize("authentication.name==#name")@GetMapping("/name")public String hello(String name) {return "hello:" + name;}@PreFilter(value = "filterObject.id%2!=0",filterTarget = "users")@PostMapping("/users")  //filterTarget 必須是 數組  集合public void addUsers(@RequestBody List<User> users) {System.out.println("users = " + users);}@PostAuthorize("returnObject.id==1")@GetMapping("/userId")public User getUserById(Integer id) {return new User(id, "blr");}@PostFilter("filterObject.id%2==0")@GetMapping("/lists")public List<User> getAll() {List<User> users = new ArrayList<>();for (int i = 0; i < 10; i++) {users.add(new User(i, "blr:" + i));}return users;}@Secured({"ROLE_USER"}) //只能判斷角色@GetMapping("/secured")public User getUserByUsername() {return new User(99, "secured");}@Secured({"ROLE_ADMIN","ROLE_USER"}) //具有其中一個即可@GetMapping("/username")public User getUserByUsername2(String username) {return new User(99, username);}@PermitAll@GetMapping("/permitAll")public String permitAll() {return "PermitAll";}@DenyAll@GetMapping("/denyAll")public String denyAll() {return "DenyAll";}@RolesAllowed({"ROLE_ADMIN","ROLE_USER"}) //具有其中一個角色即可@GetMapping("/rolesAllowed")public String rolesAllowed() {return "RolesAllowed";}
}

五、原理分析

  • ConfigAttribute 在 Spring Security 中,用戶請求一個資源(通常是一個接口或者一個 Java 方法)需要的角色會被封裝成一個ConfigAttribute 對象,在 ConfigAttribute 中只有一個 getAttribute方法,該方法返回一個 String 字符串,就是角色的名稱。
    一般來說,角色名稱都帶有一個 ROLE_ 前綴,投票器 AccessDecisionVoter 所做的事情,其實就是比較用戶所具各的角色和請求某個資源所需的 ConfigAtuibute 之間的關系。
  • AccesDecisionVoter 和 AccessDecisionManager 都有眾多的實現類,在 AccessDecisionManager 中會換個遍歷AccessDecisionVoter,進而決定是否允許用戶訪問,因而 AaccesDecisionVoter 和 AccessDecisionManager 兩者的關系類似于AuthenticationProvider 和 ProviderManager 的關系。

六、實戰

1. 簡介

在前面的案例中,我們配置的 URL 攔截規則和請求 URL 所需要的權限都是通過代碼來配置的,這樣就比較死

板,如果想要調整訪問某一個 URL 所需要的權限,就需要修改代碼。

動態管理權限規則就是我們將 URL 攔截規則和訪問 URI 所需要的權限都保存在數據庫中,這樣,在不修改源代碼

的情況下,只需要修改數據庫中的數據,就可以對權限進行調整。

用戶<--中間表--> 角色 <--中間表--> 菜單

2. 庫表設計

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for menu
-- ----------------------------
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (`id` int(11) NOT NULL AUTO_INCREMENT,`pattern` varchar(128) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of menu
-- ----------------------------
BEGIN;
INSERT INTO `menu` VALUES (1, '/admin/**');
INSERT INTO `menu` VALUES (2, '/user/**');
INSERT INTO `menu` VALUES (3, '/guest/**');
COMMIT;-- ----------------------------
-- Table structure for menu_role
-- ----------------------------
DROP TABLE IF EXISTS `menu_role`;
CREATE TABLE `menu_role` (`id` int(11) NOT NULL AUTO_INCREMENT,`mid` int(11) DEFAULT NULL,`rid` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `mid` (`mid`),KEY `rid` (`rid`),CONSTRAINT `menu_role_ibfk_1` FOREIGN KEY (`mid`) REFERENCES `menu` (`id`),CONSTRAINT `menu_role_ibfk_2` FOREIGN KEY (`rid`) REFERENCES `role` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of menu_role
-- ----------------------------
BEGIN;
INSERT INTO `menu_role` VALUES (1, 1, 1);
INSERT INTO `menu_role` VALUES (2, 2, 2);
INSERT INTO `menu_role` VALUES (3, 3, 3);
INSERT INTO `menu_role` VALUES (4, 3, 2);
COMMIT;-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) DEFAULT NULL,`nameZh` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of role
-- ----------------------------
BEGIN;
INSERT INTO `role` VALUES (1, 'ROLE_ADMIN', '系統管理員');
INSERT INTO `role` VALUES (2, 'ROLE_USER', '普通用戶');
INSERT INTO `role` VALUES (3, 'ROLE_GUEST', '游客');
COMMIT;-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(32) DEFAULT NULL,`password` varchar(255) DEFAULT NULL,`enabled` tinyint(1) DEFAULT NULL,`locked` tinyint(1) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of user
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES (1, 'admin', '{noop}123', 1, 0);
INSERT INTO `user` VALUES (2, 'user', '{noop}123', 1, 0);
INSERT INTO `user` VALUES (3, 'blr', '{noop}123', 1, 0);
COMMIT;-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (`id` int(11) NOT NULL AUTO_INCREMENT,`uid` int(11) DEFAULT NULL,`rid` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `uid` (`uid`),KEY `rid` (`rid`),CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user` (`id`),CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`rid`) REFERENCES `role` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of user_role
-- ----------------------------
BEGIN;
INSERT INTO `user_role` VALUES (1, 1, 1);
INSERT INTO `user_role` VALUES (2, 1, 2);
INSERT INTO `user_role` VALUES (3, 2, 2);
INSERT INTO `user_role` VALUES (4, 3, 3);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

3. 創建 springboot 應用

  • 引入依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version>
</dependency>
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version>
</dependency>
  • 配置配置文件
server.port=8080
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:com/blr/mapper/*.xml
mybatis.type-aliases-package=com.blr.entity
  • 創建實體類
public class User implements UserDetails {private Integer id;private String password;private String username;private boolean enabled;private boolean locked;private List<Role> roles;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList());}@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return !locked;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return enabled;}public void setId(Integer id) {this.id = id;}public void setPassword(String password) {this.password = password;}public void setUsername(String username) {this.username = username;}public void setEnabled(boolean enabled) {this.enabled = enabled;}public void setLocked(boolean locked) {this.locked = locked;}public void setRoles(List<Role> roles) {this.roles = roles;}public Integer getId() {return id;}public List<Role> getRoles() {return roles;}
}

public class Role {private Integer id;private String name;private String nameZh;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getNameZh() {return nameZh;}public void setNameZh(String nameZh) {this.nameZh = nameZh;}
}

public class Menu {private Integer id;private String pattern;private List<Role> roles;public List<Role> getRoles() {return roles;}public void setRoles(List<Role> roles) {this.roles = roles;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getPattern() {return pattern;}public void setPattern(String pattern) {this.pattern = pattern;}
}
  • 創建 mapper 接口
@Mapper
public interface UserMapper {List<Role> getUserRoleByUid(Integer uid);User loadUserByUsername(String username);
}

@Mapper
public interface MenuMapper {List<Menu> getAllMenu();
}
  • 創建 mapper 文件
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.blr.mapper.UserMapper"><select id="loadUserByUsername" resultType="com.blr.entity.User">select *from userwhere username = #{username};</select><select id="getUserRoleByUid" resultType="com.blr.entity.Role">select r.*from role r,user_role urwhere ur.uid = #{uid}and ur.rid = r.id</select>
</mapper>

<mapper namespace="com.blr.mapper.MenuMapper"><resultMap id="MenuResultMap" type="com.blr.entity.Menu"><id property="id" column="id"/><result property="pattern" column="pattern"></result><collection property="roles" ofType="com.blr.entity.Role"><id column="rid" property="id"/><result column="rname" property="name"/><result column="rnameZh" property="nameZh"/></collection></resultMap><select id="getAllMenu" resultMap="MenuResultMap">select m.*, r.id as rid, r.name as rname, r.nameZh as rnameZhfrom menu mleft join menu_role mr on m.`id` = mr.`mid`left join role r on r.`id` = mr.`rid`</select>
</mapper>
  • 創建 service 接口
@Service
public class UserService implements UserDetailsService {private final UserMapper userMapper;@Autowiredpublic UserService(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userMapper.loadUserByUsername(username);if (user == null) {throw new UsernameNotFoundException("用戶不存在");}user.setRoles(userMapper.getUserRoleByUid(user.getId()));return user;}
}

@Service
public class MenuService {private final MenuMapper menuMapper;@Autowiredpublic MenuService(MenuMapper menuMapper) {this.menuMapper = menuMapper;}public List<Menu> getAllMenu() {return menuMapper.getAllMenu();}
}
  • 創建測試 controller
@RestController
public class HelloController {@GetMapping("/admin/hello")public String admin() {return "hello admin";}@GetMapping("/user/hello")public String user() {return "hello user";}@GetMapping("/guest/hello")public String guest() {return "hello guest";}@GetMapping("/hello")public String hello() {return "hello";}
}

  • 創建 CustomSecurityMetadataSource
@Component
public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {private final MenuService menuService;@Autowiredpublic CustomSecurityMetadataSource(MenuService menuService) {this.menuService = menuService;}AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {String requestURI = ((FilterInvocation) object).getRequest().getRequestURI();List<Menu> allMenu = menuService.getAllMenu();for (Menu menu : allMenu) {if (antPathMatcher.match(menu.getPattern(), requestURI)) {String[] roles = menu.getRoles().stream().map(r -> r.getName()).toArray(String[]::new);return SecurityConfig.createList(roles);}}return null;}@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() {return null;}@Overridepublic boolean supports(Class<?> clazz) {return FilterInvocation.class.isAssignableFrom(clazz);}
}

  • 配置 Security 配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final CustomSecurityMetadataSource customSecurityMetadataSource;private final UserService userService;@Autowiredpublic SecurityConfig(CustomSecurityMetadataSource customSecurityMetadataSource, UserService userService) {this.customSecurityMetadataSource = customSecurityMetadataSource;this.userService = userService;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService);}@Overrideprotected void configure(HttpSecurity http) throws Exception {ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);http.apply(new UrlAuthorizationConfigurer<>(applicationContext)).withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {@Overridepublic <O extends FilterSecurityInterceptor> O postProcess(O object) {object.setSecurityMetadataSource(customSecurityMetadataSource);object.setRejectPublicInvocations(true);return object;}});http.formLogin().and().csrf().disable();}
}
  • 啟動入口類進行測試

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

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

相關文章

線性規劃模型

線性規劃算是數學建模中最基礎的模型了&#xff0c;其典型特征就是線性和有限資源&#xff0c;即在一組線性約束條件下&#xff0c;求解一個線性目標函數的最大值或最小值問題&#xff1a; 其中x 是決策變量向量&#xff0c;c 是目標函數系數向量&#xff0c;a 和 b 分別是約束…

華為云Flexus+DeepSeek征文|體驗華為云ModelArts快速搭建Dify-LLM應用開發平臺并創建知識庫大模型工作流查詢數據庫數據

華為云FlexusDeepSeek征文&#xff5c;體驗華為云ModelArts快速搭建Dify-LLM應用開發平臺并創建知識庫大模型工作流查詢數據庫數據 什么是華為云ModelArts 華為云ModelArts ModelArts是華為云提供的全流程AI開發平臺&#xff0c;覆蓋從數據準備到模型部署的全生命周期管理&am…

WPF中Style和Template異同

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;Style和Template是兩個核心概念&#xff0c;用于控制UI元素的外觀和行為&#xff0c;但它們的職責和使用場景有明顯區別。以下是詳細分析&#xff1a; 一、基本概念 1. Style&#xff08;樣式&am…

針對 DVWA 中 Command Injection 模塊的亂碼問題及解決辦法

目錄 根本原因 解決辦法 優化說明 適用范圍 系統兼容性 在 DVWA 的 Command Injection 模塊中執行系統命令時&#xff0c;返回結果出現亂碼&#xff08;如圖1所示&#xff09;。 根本原因 DVWA 默認使用 UTF-8 編碼&#xff0c;而部分系統命令&#xff08;如 Windows 的…

Linux獲取ImageNet數據集方法及小規模imagenet

一、數據集下載 ImageNet官方鏈接&#xff1a;ImageNet Linux命令直接下載&#xff1a; 訓練集 wget https://image-net.org/data/ILSVRC/2012/ILSVRC2012_img_train.tar --no-check-certificate驗證集 wget https://image-net.org/data/ILSVRC/2012/ILSVRC2012_img_val.t…

JAVA八股文:異常有哪些種類,可以舉幾個例子嗎?Throwable類有哪些常見方法?

Throwable、Error 與 Exception 所有的異常類型都繼承自 java.lang.Throwable。 其中 Error&#xff08;比如 OutOfMemoryError、StackOverflowError、類加載失敗等&#xff09;表示 JVM 自身或運行環境的問題&#xff0c;不應該也通常無法由應用程序去捕獲或恢復&#xff0c;…

.NetCore+Vue快速生產框架開發詳細方案

文章目錄 1. 項目概述 1.1 項目背景1.2 項目目標1.3 核心功能 2. 技術棧選擇 2.1 后端技術棧2.2 前端技術棧2.3 開發工具 3. 系統架構設計 3.1 整體架構3.2 后端架構設計3.3 前端架構設計3.4 微服務考慮 4. 后端.NET核心設計 4.1 項目結構4.2 核心模塊設計4.2.1 用戶模塊4.2.2 …

WPF學習筆記(18)觸發器Trigger

觸發器 1. 概述2. 詳解2.1. Trigger 用法2.2. MultiTrigger 用法2.3. DataTrigger 用法2.4. EventTrigger 用法 總結 1. 概述 官方文檔&#xff1a;https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.trigger?viewnetframework-4.8 2. 詳解 在Style中可以指定觸…

記本好書:矩陣力量:線性代數全彩圖解+微課+Python編程

書名&#xff1a;矩陣力量&#xff1a;線性代數全彩圖解微課Python編程 作者&#xff1a;姜偉生 出版社&#xff1a;清華大學出版社 出版時間&#xff1a;2023-06-01 ISBN&#xff1a;9787302632511 品牌方&#xff1a;清華大學出版社有限公司 發現一本好書&#xff0c;但是一…

?Webpack打包流程

Webpack打包流程的核心步驟包括初始化配置、解析入口文件、構建依賴圖、模塊轉換、資源優化和輸出文件?。該流程通過遞歸分析模塊依賴關系&#xff0c;結合加載器和插件處理各類資源&#xff0c;最終生成優化后的靜態文件。 ?核心流程概述? ?初始化配置?&#xff1a;讀取…

入門pytorch-聯邦學習

本文聯邦學習的代碼引用于https://github.com/shaoxiongji/federated-learning 本篇文章相當于帶大家讀一遍聯邦學習的代碼&#xff0c;同時加深了大家對聯邦學習和Pytorch框架的理解。 這里想簡單介紹一下聯邦學習。 聯邦學習說白了&#xff0c;就是假如有 N N N個數據擁有…

半導體和PN結

1. 什么是半導體&#xff1f; 導體&#xff0c;電阻率小&#xff0c;即電流容易通過的材料&#xff1b;Cu 絕緣體&#xff0c;導電性低&#xff0c;即電流不易通過的材料&#xff1b;塑料 半導體&#xff0c;常溫下導電性能介于導體和絕緣體之間&#xff0c;是一種導電可控的…

如何分析大語言模型(LLM)的內部表征來評估文本的“誠實性”

如何分析大語言模型(LLM)的內部表征來評估文本的“誠實性” 基于這樣一個假設:模型在生成誠實和不誠實回答時,其內部狀態會存在系統性差異 LAT :線性人工斷層掃描 我們通過一個生活化的例子來理解如何通過分析大語言模型的內部表征評估文本的“誠實性”。 場景類比:判…

【算法】動態規劃 矩陣 :62. 不同路徑

62. 不同路徑 一個機器人位于一個 m x n 網格的左上角 &#xff08;起始點在下圖中標記為 “Start” &#xff09;。 機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角&#xff08;在下圖中標記為 “Finish” &#xff09;。 問總共有多少條不同的路徑&…

LabVIEW調用Excel宏實現數據可視化

通過LabVIEW 的 ActiveX 接口&#xff0c;調用 Excel 應用程序&#xff0c;實現打開指定Excel 工作簿并運行其中宏&#xff08;如 “GraphData” 宏&#xff09;&#xff0c;將工作表數據以圖表形式展示。通過 ActiveX 自動化技術&#xff0c;打通 LabVIEW 與 Excel 交互通道&a…

初始CNN(卷積神經網絡)

卷積神經網絡&#xff08;Convolutional Neural Network&#xff0c;簡稱 CNN&#xff09;作為深度學習的重要分支&#xff0c;在圖像識別、目標檢測、語義分割等領域大放異彩。無論是手機上的人臉識別解鎖&#xff0c;還是自動駕駛汽車對道路和行人的識別&#xff0c;背后都離…

深度解析Spring Bean生命周期:從字節碼到可用對象的奇幻旅程

&#x1f331; 深度解析Spring Bean生命周期&#xff1a;從字節碼到可用對象的奇幻旅程 你是否曾困惑&#xff1a;為什么PostConstruct有時不執行&#xff1f;為什么循環依賴報錯如此難解&#xff1f;為什么AOP代理在某些場景失效&#xff1f; 本文將徹底拆解Spring Bean的16個…

MySQL 復合查詢和內外連接 -- 子查詢,多表查詢,自連接,合并查詢,表的內外連接

目錄 1. 子查詢 1.1 單行子查詢 1.2 多行子查詢 1.3 多列子查詢 1.4 在 from 子句中使用子查詢 2. 多表查詢 3. 自連接 4. 合并查詢 4.1 union 4.2 union all 5. 表的內連接 6. 表的外連接 下列先給出該博客中所用到的所有表的數據。 &#xff08;1&#xff09;部…

【STM32+LAN9252+HAL庫】EtherCAT從站搭建 保姆級教程

目錄 一、生成協議棧及XML文件 二、使用stm32CuboMX配置外設 三、協議棧移植 鑒于本人對EtherCAT的掌握程度十分有限&#xff0c;這篇文章僅作為我搭建基礎從站的過程記錄不做更多講解。本文內容主要為SPI模式的基礎搭建&#xff0c;更多深入的學習資料和細節&#xff0c;大家…

【LeetCode 熱題 100】239. 滑動窗口最大值——(解法二)滑動窗口+單調隊列

Problem: 239. 滑動窗口最大值 題目&#xff1a;給你一個整數數組 nums&#xff0c;有一個大小為 k 的滑動窗口從數組的最左側移動到數組的最右側。你只可以看到在滑動窗口內的 k 個數字。滑動窗口每次只向右移動一位。返回滑動窗口中的最大值 。 【LeetCode 熱題 100】239. 滑…