1 æç« å¯¼è¯»
Spring Security æ¯ Spring 家æä¸çä¸ä¸ªå®å ¨ç®¡çæ¡æ¶ï¼å¯ä»¥åSpring Boot项ç®å¾æ¹ä¾¿çéæãSpring Securityæ¡æ¶çä¸¤å¤§æ ¸å¿åè½ï¼è®¤è¯åææ
认è¯ï¼ éªè¯å½å访é®ç³»ç»çæ¯ä¸æ¯æ¬ç³»ç»çç¨æ·ï¼å¹¶ä¸è¦ç¡®è®¤å ·ä½æ¯åªä¸ªç¨æ·ãç®åçç解就æ¯ç»éæä½ï¼å¦æå¯ä»¥ç»å½æå就说ææ¨æ¯æ¬ç³»ç»çç¨æ·ï¼å¦ä¸è½ç»å½å°±è¯´æä¸æ¯æ¬ç³»
ç»çç¨æ·ï¼èä¸ç»å½æå以åéè¦è®°å½å½åç»å½ç¨æ·çä¿¡æ¯ï¼
ææï¼ç»è¿è®¤è¯åå¤æå½åç¨æ·æ¯å¦ææéè¿è¡æ个æä½ï¼
å¦ä¸å¾æ示就æ¯å±ç¤ºäºå½åç»å½ç¨æ·å¯ä»¥æä½çæéï¼ç¨æ·ç®¡çãè§è²ç®¡çãèå管ççï¼å¹¶ä¸é对è§è²ç®¡çå¯ä»¥è¿è¡æ°å¢ãä¿®æ¹ãå é¤ã导åºçæéã
èç°å¨åå端å离å¼åæ为äºä¸»æµçå¼åæ¹å¼ï¼é£ä¹å¨åå端å离å¼åæ¹å¼ä¸å¦ä½ä½¿ç¨Spring Securityå°±æ¯æ¬æç« éè¦éç¹ç 究çå 容ã
2 Spring Security认è¯åè½
2.1 å端å离项ç®ç认è¯æµç¨
è¦æ³äºè§£å¦æ使ç¨Spring Securityè¿è¡è®¤è¯ï¼é£ä¹å°±éè¦å äºè§£ä¸ä¸åå端å离项ç®ä¸ç认è¯æµç¨ï¼å¦ä¸æ示ï¼
2.2 Spring Securityåçåæ¢
è¦æ³ä½¿ç¨Spring Securityæ¡æ¶æ¥å®ç°ä¸è¿°ç认è¯æä½ï¼å°±å¿ é¡»å è¦äºè§£ä¸ä¸ªSpring Securityæ¡æ¶çå·¥ä½æµç¨ã
2.2.1 è¿æ»¤å¨é¾
Spring Securityçåçå ¶å®å°±æ¯ä¸ä¸ªè¿æ»¤å¨é¾ï¼å é¨å å«äºæä¾åç§åè½çè¿æ»¤å¨ãè¿éæ们å¯ä»¥ççå ¥é¨æ¡ä¾ä¸çè¿æ»¤å¨ã
å¾ä¸åªå±ç¤ºäºæ ¸å¿è¿æ»¤å¨ï¼å ¶å®çéæ ¸å¿è¿æ»¤å¨å¹¶æ²¡æå¨å¾ä¸å±ç¤ºã
UsernamePasswordAuthenticationFilter: è´è´£å¤çæ们å¨ç»é页é¢å¡«åäºç¨æ·åå¯ç åçç»é请æ±ã
ExceptionTranslationFilterï¼å¤çè¿æ»¤å¨é¾ä¸æåºçä»»ä½AccessDeniedExceptionåAuthenticationException ã
FilterSecurityInterceptorï¼è´è´£æéæ ¡éªçè¿æ»¤å¨ã
2.2.2 认è¯æµç¨
Spring Securityç认è¯æµç¨å¤§è´å¦ä¸æ示ï¼
æ¦å¿µéæ¥:
Authenticationæ¥å£: å®çå®ç°ç±»ï¼è¡¨ç¤ºå½å访é®ç³»ç»çç¨æ·ï¼å°è£ äºç¨æ·ç¸å ³ä¿¡æ¯ã
AuthenticationManageræ¥å£ï¼å®ä¹äºè®¤è¯Authenticationçæ¹æ³
UserDetailsServiceæ¥å£ï¼å è½½ç¨æ·ç¹å®æ°æ®çæ ¸å¿æ¥å£ãéé¢å®ä¹äºä¸ä¸ªæ ¹æ®ç¨æ·åæ¥è¯¢ç¨æ·ä¿¡æ¯çæ¹æ³ã
UserDetailsæ¥å£ï¼æä¾æ ¸å¿ç¨æ·ä¿¡æ¯ãéè¿UserDetailsServiceæ ¹æ®ç¨æ·åè·åå¤ççç¨æ·ä¿¡æ¯è¦å°è£ æUserDetails对象è¿åãç¶åå°è¿äºä¿¡æ¯å°è£ å°Authentication对象ä¸ã
2.3 认è¯å®ç°
å¨åå端å离项ç®ä¸ï¼å端请æ±çæ¯æ们èªå·±å®ä¹ç认è¯æ¥å£ãå 为å¨è®¤è¯æå以åå°±éè¦é对å½åç¨æ·çætokenï¼Spring Securityä¸æä¾çåå§è®¤è¯å°±æ æ³å®ç°äºãå¨æ们èªå®
ä¹ç认è¯æ¥å£ä¸ï¼éè¦è°ç¨Spring SecurityçAPIåå©äºSpring Securityå®ç°è®¤è¯ã
2.3.1 æè·¯åæ
认è¯ï¼
1ãèªå®ä¹è®¤è¯æ¥å£
â è°ç¨ProviderManagerçæ¹æ³è¿è¡è®¤è¯ å¦æ认è¯éè¿çæjwt
â¡ æç¨æ·ä¿¡æ¯åå ¥redisä¸
2ãèªå®ä¹UserDetailsService
â å¨è¿ä¸ªå®ç°ç±»ä¸å»æ¥è¯¢æ°æ®åº
æ ¡éªï¼
1ãå®ä¹Jwt认è¯è¿æ»¤å¨
â è·åtoken
⡠解ætokenè·åå ¶ä¸çuserid
⢠ä»redisä¸è·åç¨æ·ä¿¡æ¯
⣠åå ¥SecurityContextHolder
2.3.2 éæRedis
æ·»å ä¾èµ
<!--redisä¾èµ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
æ·»å redisé ç½®
å¨application.ymlæ件ä¸æ·»å Redisçç¸å ³é ç½®
spring:
redis:
host: 127.0.0.1
port: 6379
2.3.3 éæMybatis Plus
æ·»å ä¾èµ
<!-- å¼å
¥mybatis plusçä¾èµ -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!-- æ°æ®åºé©±å¨ -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombokä¾èµå
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
å建æ°æ®åºè¡¨
CREATE TABLE `sys_user` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主é®',
`user_name` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT 'ç¨æ·å',
`nick_name` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT 'æµç§°',
`password` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT 'å¯ç ',
`status` CHAR(1) DEFAULT '0' COMMENT 'è´¦å·ç¶æï¼0æ£å¸¸ 1åç¨ï¼',
`email` VARCHAR(64) DEFAULT NULL COMMENT 'é®ç®±',
`phone_number` VARCHAR(32) DEFAULT NULL COMMENT 'ææºå·',
`sex` CHAR(1) DEFAULT NULL COMMENT 'ç¨æ·æ§å«ï¼0ç·ï¼1女ï¼2æªç¥ï¼',
`avatar` VARCHAR(128) DEFAULT NULL COMMENT '头å',
`user_type` CHAR(1) NOT NULL DEFAULT '1' COMMENT 'ç¨æ·ç±»åï¼0管çåï¼1æ®éç¨æ·ï¼',
`create_by` BIGINT(20) DEFAULT NULL COMMENT 'å建人çç¨æ·id',
`create_time` DATETIME DEFAULT NULL COMMENT 'å建æ¶é´',
`update_by` BIGINT(20) DEFAULT NULL COMMENT 'æ´æ°äºº',
`update_time` DATETIME DEFAULT NULL COMMENT 'æ´æ°æ¶é´',
`del_flag` INT(11) DEFAULT '0' COMMENT 'å é¤æ å¿ï¼0代表æªå é¤ï¼1代表已å é¤ï¼',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='ç¨æ·è¡¨'
-- æå
¥æ°æ®
insert into security.sys_user (id, user_name, nick_name, password, status, email, phone_number, sex, avatar, user_type, create_by, create_time, update_by, update_time, del_flag) values (1501123580308578309, 'zhangsan', 'å¼ ä¸', '1234', '0', '[email protected]', '1312103105', '0', 'http://www.itcast.cn', '1', 1, '2022-03-08 09:12:06', 1, '2022-03-08 09:12:06', 0);
æ°æ®åºç¸å ³é ç½®
spring:
datasource:
url: jdbc:mysql://localhost:3306/security?characterEncoding=utf-8&serverTimezone=UTC
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis plusçé
ç½®
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: assign_id
Userå®ä½ç±»
@Data
@TableName(value = "sys_user")
public class User {
@TableId
private Long id ; // å¯ä¸æ è¯
private String userName ; // ç¨æ·å
private String nickName ; // æµç§°
private String password ; // å¯ç
private String status ; // ç¶æ è´¦å·ç¶æï¼0æ£å¸¸ 1åç¨ï¼
private String email ; // é®ç®±
private String phoneNumber ; // çµè¯å·ç
private String sex ; // æ§å« ç¨æ·æ§å«ï¼0ç·ï¼1女ï¼2æªç¥ï¼
private String avatar ; // ç¨æ·å¤´å
private String userType ; // ç¨æ·ç±»å ï¼0管çåï¼1æ®éç¨æ·ï¼
private Long createBy ; // å建人
private Date createTime ; // å建æ¶é´
private Long updateBy ; // æ´æ°äºº
private Date updateTime ; // æ´æ°æ¶é´
private Integer delFlag ; // æ¯å¦å é¤ ï¼0代表æªå é¤ï¼1代表已å é¤ï¼
}
UserMapperæ¥å£
public interface UserMapper extends BaseMapper<User> { }
å¯å¨ç±»
@SpringBootApplication
@MapperScan(basePackages = "com.itheima.security.mapper")
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class , args) ;
}
}
2.3.4 éæJunit
æ·»å ä¾èµ
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
ç¼åæµè¯ç±»
@SpringBootTest(classes = SecurityApplication.class)
public class SecurityApplicationTest {
@Autowired
private UserMapper userMapper ;
@Test
public void findAll() {
List<User> selectList = userMapper.selectList(new LambdaQueryWrapper<User>());
selectList.forEach( s -> System.out.println(s) );
}
}
2.3.5 UserDetailsService
å¨Spring Securityçæ´ä¸ªè®¤è¯æµç¨ä¸ä¼è°ç¨ä¼è°ç¨UserDetailsServiceä¸çloadUserByUsernameæ¹æ³æ ¹æ®ç¨æ·å称æ¥è¯¢ç¨æ·æ°æ®ãé»è®¤æ åµä¸è°ç¨çæ¯
InMemoryUserDetailsManagerä¸çæ¹æ³ï¼è¯¥UserDetailsServiceæ¯ä»å åä¸è·åç¨æ·çæ°æ®ãç°å¨æ们éè¦ä»æ°æ®åºä¸è·åç¨æ·çæ°æ®ï¼é£ä¹æ¤æ¶å°±éè¦èªå®ä¹ä¸ä¸ª
UserDetailsServiceæ¥è¦çé»è®¤çé ç½®ã
UserDetailsServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper ;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// æ ¹æ®ç¨æ·åæ¥è¯¢ç¨æ·æ°æ®
LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.<User>lambdaQuery().eq(User::getUserName ,username) ;
User user = userMapper.selectOne(lambdaQueryWrapper);
// å¦ææ¥è¯¢ä¸å°æ°æ®ï¼è¯´æç¨æ·åæè
å¯ç é误ï¼ç´æ¥æåºå¼å¸¸
if(user == null) {
throw new RuntimeException("ç¨æ·åæè
å¯ç é误") ;
}
// å°æ¥è¯¢å°ç对象转æ¢æSpring Securityæéè¦çUserDetails对象
return new LoginUser(user);
}
}
LoginUser
package com.itheima.security.domain;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
// ç¨æ¥å°è£
æ°æ®åºæ¥è¯¢åºæ¥çç¨æ·æ°æ®
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {
private User user ;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUserName();
}
@Override
public boolean isAccountNonExpired() { // è´¦å·æ¯å¦æ²¡æè¿æ
return true;
}
@Override
public boolean isAccountNonLocked() { // è´¦å·æ¯å¦æ²¡æ被éå®
return true;
}
@Override
public boolean isCredentialsNonExpired() { // è´¦å·çåè¯æ¯å¦æ²¡æè¿æ
return true;
}
@Override
public boolean isEnabled() { // è´¦å·æ¯å¦å¯ç¨
return true;
}
}
æµè¯è®¤è¯
å éè¿Spring Securityæä¾çé»è®¤ç»å½æ¥å£è¿è¡è®¤è¯çæµè¯ï¼éè¦å¯å¨Redisãæ¤æ¶æ§å¶å°ä¼è¾åºå¦ä¸é误ï¼
æ¥éçåå ï¼é»è®¤æ åµä¸Spring Securityå¨è·åå°UserDetailsServiceè¿åçç¨æ·ä¿¡æ¯ä»¥åï¼ä¼è°ç¨PasswordEncoderä¸çmatchesæ¹æ³è¿è¡æ ¡éªï¼ä½æ¯æ¤æ¶å¨Spring容å¨ä¸å¹¶ä¸
åå¨ä»»ä½çPasswordEncoderç对象ï¼å æ¤æ æ³å®ææ ¡éªæä½ã
解å³æ¹æ¡ï¼
â 使ç¨ææ认è¯
è¦ä½¿ç¨ææè¿è¡è®¤è¯ï¼å°±éè¦å¨å¯ç å段å¼çåé¢æ·»å {noop}åæ ·ï¼
â¡ é ç½®å å¯ç®æ³
2.3.6 é ç½®å å¯ç®æ³
ä¸è¬æ åµä¸å ³äºå¯ç å¨æ°æ®åºä¸é½æ¯å¯æåå¨çï¼å¨è¿è¡è®¤è¯çæ¶åé½æ¯åºäºå¯æè¿è¡æ ¡éªãå ·ä½çå®ç°æ¥éª¤ï¼
1ã使ç¨æå®çå å¯ç®æ³ãBCryptã对å¯ç è¿è¡å å¯å¤çï¼å°å å¯ä»¥åçå¯æåå¨å°æ°æ®åºä¸
2ãå¨Spring容å¨ä¸æ³¨å ¥ä¸ä¸ªPasswordEncoder对象ï¼ä¸è¬æ åµä¸æ³¨å ¥çå°±æ¯ï¼BCryptPasswordEncoder
æ们å¯ä»¥å®ä¹ä¸ä¸ªSpring Securityçé 置类ï¼Spring Securityè¦æ±è¿ä¸ªé 置类è¦ç»§æ¿WebSecurityConfigurerAdapterã
@Configuration
public class SpringSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder() ;
}
}
æµè¯ï¼å°æ°æ®åºçç¨æ·å¯ç æ´æ¹ä¸ºä½¿ç¨BCryptPasswordEncoderå å¯ä»¥åçå¯æ
@SpringBootTest(classes = SecurityApplication.class)
public class SecurityApplicationTest {
@Autowired
private PasswordEncoder passwordEncoder ;
@Test
public void testBcrypt() {
// å å¯æµè¯
String encode = passwordEncoder.encode("1234");
System.out.println(encode);
// æ ¡éªæµè¯
boolean matches = passwordEncoder.matches("1234", "$2a$10$ZqVB18PPA3P/MR9So/i8N.1UvVb.PblNl2sbj6pQJNDCgqiZqNQUm");
System.out.println(matches);
}
}
2.3.7 ç»å½æ¥å£
æ´ä½å®ç°æè·¯ï¼
â æ¥ä¸æ们éè¦èªå®ä¹ç»éæ¥å£ï¼ç¶å让Spring Security对è¿ä¸ªæ¥å£æ¾è¡,让ç¨æ·è®¿é®è¿ä¸ªæ¥å£çæ¶åä¸ç¨ç»å½ä¹è½è®¿é®ã
â¡ å¨æ¥å£ä¸æ们éè¿AuthenticationManagerçauthenticateæ¹æ³æ¥è¿è¡ç¨æ·è®¤è¯,æ以éè¦å¨Security Configä¸é ç½®æAuthenticationManageræ³¨å ¥å®¹å¨ã
⢠认è¯æåçè¯è¦çæä¸ä¸ªjwtï¼å°jwt令çè¿è¡è¿åã并ä¸ä¸ºäºè®©ç¨æ·ä¸å请æ±æ¶è½éè¿jwtè¯å«åºå ·ä½çæ¯åªä¸ªç¨æ·ï¼å¨è¿åä¹åï¼æ们éè¦æç¨æ·ä¿¡æ¯åå ¥redisï¼å¯ä»¥æç¨æ·id
ä½ä¸ºkeyã
æ¦æªè§åé ç½®
å¨SpringSecurityConfigurerä¸éåconfigure(HttpSecurity http)æ¹æ³ï¼
// é
ç½®Spring Securityçæ¦æªè§å
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // å
³écsrf
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // æå®sessionçå建çç¥ï¼ä¸ä½¿ç¨session
.and() // å次è·åå°HttpSecurity对象
.authorizeRequests() // è¿è¡è®¤è¯è¯·æ±çé
ç½®
.antMatchers("/user/login").anonymous() // 对äºç»å½æ¥å£ï¼å
许å¿å访é®
.anyRequest().authenticated(); // é¤äºä¸é¢ç请æ±ä»¥å¤ææç请æ±å
¨é¨éè¦è®¤è¯
}
Spring容å¨æ³¨åAuthenticationManager
å¨SpringSecurityConfigurerä¸éåauthenticationManagerBeanæ¹æ³ï¼
ç»å½æ¥å£å®ä¹
UserController
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Autowired
private UserService userService ;
@PostMapping(value = "/login")
public ResponseResult<Map> login(@RequestBody User user) {
return userService.login(user) ;
}
}
ResponseResult
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResponseResult<T> {
private Integer code ;
private String msg ;
private T data ;
}
UserService
@Service
public class UserServiceImpl implements UserService {
@Autowired
private AuthenticationManager authenticationManager ;
@Autowired
private RedisTemplate<String , String> redisTemplate ;
@Override
public ResponseResult<Map> login(User user) {
// å建Authentication对象
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName() , user.getPassword()) ;
// è°ç¨AuthenticationManagerçauthenticateæ¹æ³è¿è¡è®¤è¯
Authentication authentication = authenticationManager.authenticate(authenticationToken);
if(authentication == null) {
throw new RuntimeException("ç¨æ·åæå¯ç é误");
}
// å°ç¨æ·çæ°æ®åå¨å°Redisä¸
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
String userId = loginUser.getUser().getId().toString();
redisTemplate.boundValueOps("login_user:" + userId).set(JSON.toJSONString(loginUser));
// çæJWT令ç并è¿è¡è¿å
Map<String , String> params = new HashMap<>() ;
params.put("userId" , userId) ;
String token = JwtUtils.getToken(params);
// æ建è¿åæ°æ®
Map<String , String> result = new HashMap<>();
result.put("token" , token) ;
return new ResponseResult<Map>(200 , "æä½æå" , result);
}
}
2.3.8 认è¯è¿æ»¤å¨
å½ç¨æ·å¨è®¿é®æ们åä¿æ¤çèµæºçæ¶åï¼å°±éè¦æ ¡éªç¨æ·æ¯å¦å·²ç»ç»å½ãæ们éè¦èªå®ä¹ä¸ä¸ªè¿æ»¤å¨è¿è¡å®ç°ã
è¿æ»¤å¨å é¨çé»è¾ï¼
1ãè·å请æ±å¤´ä¸çtokenï¼å¯¹tokenè¿è¡è§£æ
2ãååºå ¶ä¸çuserid
3ã使ç¨useridå»redisä¸è·å对åºçLoginUser对象ã
4ãç¶åå°è£ Authentication对象åå ¥SecurityContextHolder
5ãæ¾è¡
注æï¼è¿ä¸ªè¿æ»¤å¨éè¦å°å ¶å å ¥å°Spring Securityçè¿æ»¤å¨é¾ä¸
认è¯è¿æ»¤å¨ï¼
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private RedisTemplate<String , String> redisTemplate ;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 1ãä»è¯·æ±å¤´ä¸è·åtokenï¼å¦æ请æ±å¤´ä¸ä¸åå¨tokenï¼ç´æ¥æ¾è¡å³å¯ï¼ç±Spring Securityçè¿æ»¤å¨è¿è¡æ ¡éªï¼
String token = request.getHeader("token");
if(token == null || "".equals(token)) {
filterChain.doFilter(request , response);
return ;
}
// 2ã对tokenè¿è¡è§£æï¼ååºå
¶ä¸çuserId
String userId = null ;
try {
Claims claims = JwtUtils.getClaims(token);
userId= claims.get("userId").toString();
}catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("tokenéæ³") ;
}
// 3ã使ç¨userIdä»redisä¸æ¥è¯¢å¯¹åºçLoginUser对象
String loginUserJson = redisTemplate.boundValueOps("login_user:" + userId).get();
LoginUser loginUser = JSON.parseObject(loginUserJson, LoginUser.class);
if(loginUser != null) {
// 4ãç¶åå°æ¥è¯¢å°çLoginUser对象çç¸å
³ä¿¡æ¯å°è£
å°UsernamePasswordAuthenticationToken对象ä¸ï¼ç¶åå°è¯¥å¯¹è±¡åå¨å°Securityçä¸ä¸æ对象ä¸
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null , null) ;
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
// 5ãæ¾è¡
filterChain.doFilter(request , response);
}
}
é ç½®è¿æ»¤å¨ï¼
2.3.9 éåºç»å½
æ们åªéè¦å®ä¹ä¸ä¸ªéåºæ¥å£ï¼ç¶åè·åSecurityContextHolderä¸ç认è¯ä¿¡æ¯ï¼å é¤redisä¸å¯¹åºçæ°æ®å³å¯ã
UserServiceæ·»å éåºç»å½æ¥å£ï¼
@Override
public ResponseResult logout() {
// è·åç»å½çç¨æ·ä¿¡æ¯
LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Long userId = loginUser.getUser().getId();
// å é¤Redisä¸çç¨æ·æ°æ®
redisTemplate.delete("login_user:" + userId) ;
// è¿å
return new ResponseResult(200 , "éåºæå" , null) ;
}
3 Spring Securityææåè½
3.1 æéç³»ç»çä½ç¨
æéç³»ç»ä½ç¨ï¼ä¿è¯ç³»ç»çå®å ¨æ§
举ä¾ï¼ä¾å¦ä¸ä¸ªå¦æ ¡å¾ä¹¦é¦ç管çç³»ç»ï¼å¦ææ¯æ®éå¦çç»å½ä»¥å使ç¨å书åè¿ä¹¦çåè½ï¼ä¸å¯è½è®©ä»å ·ææ·»å 书ç±ä¿¡æ¯ï¼å é¤ä¹¦ç±ä¿¡æ¯çåè½ãä½æ¯å¦ææ¯ä¸ä¸ªå¾ä¹¦é¦ç®¡çåçè´¦
å·ç»å½äºï¼åºè¯¥å°±è½çå°å¹¶ä½¿ç¨æ·»å 书ç±ä¿¡æ¯ï¼å é¤ä¹¦ç±ä¿¡æ¯çåè½ãæ»ç»èµ·æ¥å°±æ¯ä¸åçç¨æ·å¯ä»¥ä½¿ç¨ä¸åçåè½ï¼è¿å°±æ¯æéç³»ç»è¦å»å®ç°çææã
æéåè½çå®ç°æ们ä¸è½åªä¾èµå端å»æ ¹æ®ç¨æ·çæéæ¥éæ©æ¾ç¤ºåªäºèåãåªäºæé®ãå 为å¦ææ人ç¥éäºå¯¹åºåè½çæ¥å£å°åå°±å¯ä»¥ä¸éè¿å端ï¼ç´æ¥å»åé请æ±æ¥å®ç°ç¸å ³å
è½æä½ãæ以æ们è¿éè¦å¨åå°è¿è¡ç¨æ·æéçå¤æï¼å¤æå½åç¨æ·æ¯å¦æç¸åºçæéï¼å¿ é¡»å ·ææéæéæè½è¿è¡ç¸åºçæä½ã
3.2 ææåºæ¬æµç¨
å¨Spring Securityä¸ï¼ä¼ä½¿ç¨é»è®¤çFilterSecurityInterceptoræ¥è¿è¡æéæ ¡éªãå¨FilterSecurityInterceptorä¸ä¼ä»SecurityContextHolderè·åå ¶ä¸çAuthenticationï¼ç¶å
è·åå ¶ä¸çæéä¿¡æ¯ãå½åç¨æ·æ¯å¦æ¥æ访é®å½åèµæºæéçæéãæ以æ们å¨é¡¹ç®ä¸åªéè¦æå½åç»å½ç¨æ·çæéä¿¡æ¯ä¹åå ¥Authenticationãç¶å设置æ们çèµæºæéè¦çæé
å³å¯ã
3.3 å ¥é¨æ¡ä¾
3.3.1 èµæºæ·»å æéæé
Spring Security为æ们æä¾äºåºäºæ³¨è§£çæéæ§å¶æ¹æ¡ï¼è¿ä¹æ¯æ们项ç®ä¸ä¸»è¦éç¨çæ¹å¼ãæ们å¯ä»¥ä½¿ç¨æ³¨è§£å»æå®è®¿é®å¯¹åºçèµæºæéçæéãä½æ¯è¦ä½¿ç¨å®æ们éè¦å å¼å¯
ç¸å ³é ç½®ã
å¼å¯æéé ç½®åè½
å¨å¯å¨ç±»ä¸æ·»å @EnableGlobalMethodSecurity(prePostEnabled = true)
æ¹æ³æ·»å æéæé
ä¸ç»ç¨æ·æ·»å ä»»ä½æéä¿¡æ¯è¿è¡æµè¯ï¼è¿åä¿¡æ¯ä¸ºï¼
{
"timestamp": "2022-07-04T06:31:47.821+00:00",
"status": 403,
"error": "Forbidden",
"path": "/hello"
}
3.3.2 ç¨æ·æ·»å ææ¥æçæé
UserDetailsServiceImpl
å¨UserDetailsServiceImplä¸æ建æµè¯çæéæ°æ®ï¼å¹¶å°å ¶è®¾ç½®ç»LoginUser对象ï¼
LoginUser
LoginUseræ¥æ¶æéæ°æ®ï¼å¹¶ä¸å¯¹getAuthoritiesæ¹æ³è¿è¡æ¹é ï¼è¿åSpring Securityæéè¦çæé对象ï¼
JwtAuthenticationTokenFilter
å¨JWTè¿æ»¤å¨ä¸éè¦ä»Redisä¸è·åLoginUser对象ï¼å¨æ建UsernamePasswordAuthenticationToken对象çæ¶åï¼ä¸ºå ¶è®¾ç½®æéæ°æ®ï¼
3.4 ä»æ°æ®åºæ¥è¯¢æéä¿¡æ¯
3.4.1 RBACæé模å
RBACæé模åï¼Role-Based Access Controlï¼å³ï¼åºäºè§è²çæéæ§å¶ãè¿æ¯ç®åæ常被å¼åè 使ç¨ä¹æ¯ç¸å¯¹æç¨ãéç¨æé模åã
3.4.2 ç¯å¢åå¤
æ°æ®åºç¯å¢åå¤
æé表(èå表)ï¼
CREATE TABLE `sys_menu` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`menu_name` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT 'èåå',
`path` varchar(200) DEFAULT NULL COMMENT 'è·¯ç±å°å',
`component` varchar(255) DEFAULT NULL COMMENT 'ç»ä»¶è·¯å¾',
`visible` char(1) DEFAULT '0' COMMENT 'èåç¶æï¼0æ¾ç¤º 1éèï¼',
`status` char(1) DEFAULT '0' COMMENT 'èåç¶æï¼0æ£å¸¸ 1åç¨ï¼',
`perms` varchar(100) DEFAULT NULL COMMENT 'æéæ è¯',
`icon` varchar(100) DEFAULT '#' COMMENT 'èåå¾æ ',
`create_by` bigint(20) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_by` bigint(20) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`del_flag` int(11) DEFAULT '0' COMMENT 'æ¯å¦å é¤ï¼0æªå é¤ 1å·²å é¤ï¼',
`remark` varchar(500) DEFAULT NULL COMMENT 'å¤æ³¨',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='èå表';
# æå
¥åºç¡æ°æ®
insert into security.sys_menu (id, menu_name, path, component, visible, status, perms, icon, create_by, create_time, update_by, update_time, del_flag, remark) values (1543917775762886657, 'æ·»å ç¨æ·', '/user/addUser', 'addUser', '0', '0', 'system:user:add', 'icon-add', 1, '2022-07-04 11:20:57', 1, '2022-07-04 11:20:57', 0, 'æ·»å ç¨æ·æé®');
insert into security.sys_menu (id, menu_name, path, component, visible, status, perms, icon, create_by, create_time, update_by, update_time, del_flag, remark) values (1543918065589379073, 'æ¥çç¨æ·å表', '/user/userList', 'userList', '0', '0', 'system:user:list', 'icon-list', 1, '2022-07-04 11:22:06', 1, '2022-07-04 11:22:06', 0, 'æ¥çç¨æ·å表ç¨æ·æé®');
è§è²è¡¨ï¼
CREATE TABLE `sys_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(128) DEFAULT NULL,
`role_key` varchar(100) DEFAULT NULL COMMENT 'è§è²æéå符串',
`status` char(1) DEFAULT '0' COMMENT 'è§è²ç¶æï¼0æ£å¸¸ 1åç¨ï¼',
`del_flag` int(1) DEFAULT '0' COMMENT 'del_flag',
`create_by` bigint(200) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_by` bigint(200) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`remark` varchar(500) DEFAULT NULL COMMENT 'å¤æ³¨',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='è§è²è¡¨';
# æå
¥æµè¯æ°æ®
insert into security.sys_role (id, name, role_key, status, del_flag, create_by, create_time, update_by, update_time, remark) values (1, 'ç³»ç»ç®¡çå', 'admin', '0', 0, 1, '2022-07-04 19:25:06', 1, '2022-07-04 19:25:19', 'ç³»ç»ç®¡çå');
insert into security.sys_role (id, name, role_key, status, del_flag, create_by, create_time, update_by, update_time, remark) values (2, 'æ®éç¨æ·', 'user', '0', 0, 1, '2022-07-04 19:25:48', 1, '2022-07-04 19:25:52', 'æ®éç¨æ·è§è²');
è§è²èåä¸é´è¡¨ï¼
CREATE TABLE `sys_role_menu` (
`role_id` bigint(200) NOT NULL AUTO_INCREMENT COMMENT 'è§è²ID',
`menu_id` bigint(200) NOT NULL DEFAULT '0' COMMENT 'èåid',
PRIMARY KEY (`role_id`,`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
# æå
¥åºç¡æµè¯æ°æ®
insert into security.sys_role_menu (role_id, menu_id) values (1, 1543917775762886657);
insert into security.sys_role_menu (role_id, menu_id) values (1, 1543918065589379073);
insert into security.sys_role_menu (role_id, menu_id) values (2, 1543918065589379073);
ç¨æ·è¡¨ï¼
CREATE TABLE `sys_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主é®',
`user_name` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT 'ç¨æ·å',
`nick_name` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT 'æµç§°',
`password` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT 'å¯ç ',
`status` char(1) DEFAULT '0' COMMENT 'è´¦å·ç¶æï¼0æ£å¸¸ 1åç¨ï¼',
`email` varchar(64) DEFAULT NULL COMMENT 'é®ç®±',
`phone_number` varchar(32) DEFAULT NULL COMMENT 'ææºå·',
`sex` char(1) DEFAULT NULL COMMENT 'ç¨æ·æ§å«ï¼0ç·ï¼1女ï¼2æªç¥ï¼',
`avatar` varchar(128) DEFAULT NULL COMMENT '头å',
`user_type` char(1) NOT NULL DEFAULT '1' COMMENT 'ç¨æ·ç±»åï¼0管çåï¼1æ®éç¨æ·ï¼',
`create_by` bigint(20) DEFAULT NULL COMMENT 'å建人çç¨æ·id',
`create_time` datetime DEFAULT NULL COMMENT 'å建æ¶é´',
`update_by` bigint(20) DEFAULT NULL COMMENT 'æ´æ°äºº',
`update_time` datetime DEFAULT NULL COMMENT 'æ´æ°æ¶é´',
`del_flag` int(11) DEFAULT '0' COMMENT 'å é¤æ å¿ï¼0代表æªå é¤ï¼1代表已å é¤ï¼',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='ç¨æ·è¡¨';
# æå
¥æµè¯æ°æ®
insert into security.sys_user (id, user_name, nick_name, password, status, email, phone_number, sex, avatar, user_type, create_by, create_time, update_by, update_time, del_flag) values (1501123580308578309, 'zhangsan', 'å¼ ä¸', '$2a$10$ZqVB18PPA3P/MR9So/i8N.1UvVb.PblNl2sbj6pQJNDCgqiZqNQUm', '0', '[email protected]', '1312103105', '0', 'http://www.itcast.cn', '1', 1, '2022-03-08 09:12:06', 1, '2022-03-08 09:12:06', 0);
insert into security.sys_user (id, user_name, nick_name, password, status, email, phone_number, sex, avatar, user_type, create_by, create_time, update_by, update_time, del_flag) values (1501123580308578310, 'admin', 'ç³»ç»ç®¡çå', '$2a$10$ZqVB18PPA3P/MR9So/i8N.1UvVb.PblNl2sbj6pQJNDCgqiZqNQUm', '0', '[email protected]', '1312103105', '0', 'http://www.itcast.cn', '1', 1, '2022-03-08 09:12:06', 1, '2022-03-08 09:12:06', 0);
ç¨æ·è§è²ä¸é´è¡¨ï¼
CREATE TABLE `sys_user_role` (
`user_id` bigint(200) NOT NULL AUTO_INCREMENT COMMENT 'ç¨æ·id',
`role_id` bigint(200) NOT NULL DEFAULT '0' COMMENT 'è§è²id',
PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# æå
¥åºç¡æ°æ®
insert into security.sys_user_role (user_id, role_id) values (1501123580308578309, 2);
insert into security.sys_user_role (user_id, role_id) values (1501123580308578310, 1);
SQLæµè¯æ¥è¯¢æä¸ä¸ªç¨æ·æå ·æçæéï¼
SELECT distinct m.perms FROM sys_user u
left join sys_user_role ur on ur.user_id = u.id
left join sys_role_menu rm on rm.role_id = ur.role_id
left join sys_menu m on m.id = rm.menu_id
WHERE u.id = 1501123580308578310 ;
Menuå®ä½ç±»
// èå表(Menu)å®ä½ç±»
@TableName(value="sys_menu")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Menu {
@TableId
private Long id;
private String menuName; // èåå
private String path; // è·¯ç±å°å
private String component; // ç»ä»¶è·¯å¾
private String visible; // èåç¶æï¼0æ¾ç¤º 1éèï¼
private String status; // èåç¶æï¼0æ£å¸¸ 1åç¨ï¼
private String perms; // æéæ è¯
private String icon; // èåå¾æ
private Long createBy; // å建人
private Date createTime; // å建æ¶é´
private Long updateBy; // æ´æ°äºº
private Date updateTime; // æ´æ°æ¶é´
private Integer delFlag; // æ¯å¦å é¤ï¼0æªå é¤ 1å·²å é¤ï¼
private String remark; // å¤æ³¨
}
MenuMapperæ¥å£
// æä½èå表çMapperæ¥å£
public interface MenuMapper extends BaseMapper<Menu> {
// æ¥è¯¢æä¸ä¸ªç¨æ·çæéä¿¡æ¯
public abstract List<String> findUserMenuById(Long userId) ;
}
application.ymlä¿®æ¹
MenuMapper.xmlæ å°æ件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.itheima.security.mapper.MenuMapper">
<select id="findUserMenuById" resultType="java.lang.String">
SELECT distinct m.perms FROM sys_user u
left join sys_user_role ur on ur.user_id = u.id
left join sys_role_menu rm on rm.role_id = ur.role_id
left join sys_menu m on m.id = rm.menu_id
WHERE u.id = #{userId} ;
</select>
</mapper>
3.4.3 UserDetailsServiceä¿®æ¹
ä»æ°æ®åºä¸æ¥è¯¢è¯¥ç¨æ·ççå®æéä¿¡æ¯ï¼
4 èªå®ä¹å¤±è´¥å¤ç
4.1 å®ç°æè·¯
æ们è¿å¸æå¨è®¤è¯å¤±è´¥æè æ¯ææ失败çæ åµä¸ä¹è½åæ们çæ¥å£ä¸æ ·è¿åç¸åç»æçjsonï¼è¿æ ·å¯ä»¥è®©å端è½å¯¹ååºè¿è¡ç»ä¸çå¤çãè¦å®ç°è¿ä¸ªåè½æ们éè¦ç¥é
SpringSecurityçå¼å¸¸å¤çæºå¶ã
å¨SpringSecurityä¸ï¼å¦ææ们å¨è®¤è¯æè ææçè¿ç¨ä¸åºç°äºå¼å¸¸ä¼è¢«ExceptionTranslationFilteræè·å°ãå¨ExceptionTranslationFilterä¸ä¼å»å¤ææ¯è®¤è¯å¤±è´¥è¿æ¯ææ失败åº
ç°çå¼å¸¸ã
â å¦ææ¯è®¤è¯è¿ç¨ä¸åºç°çå¼å¸¸ä¼è¢«å°è£ æAuthenticationExceptionç¶åè°ç¨AuthenticationEntryPoint对象çæ¹æ³å»è¿è¡å¼å¸¸å¤çã
â¡ å¦ææ¯ææè¿ç¨ä¸åºç°çå¼å¸¸ä¼è¢«å°è£ æAccessDeniedExceptionç¶åè°ç¨AccessDeniedHandler对象çæ¹æ³å»è¿è¡å¼å¸¸å¤çã
æ以å¦ææ们éè¦èªå®ä¹å¼å¸¸å¤çï¼æ们åªéè¦èªå®ä¹AuthenticationEntryPointåAccessDeniedHandlerç¶åé ç½®ç»Spring Securityå³å¯ã
4.5 代ç å®ç°
4.5.1 认è¯å¤±è´¥å¤çå¨
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
ResponseResult result = new ResponseResult(HttpStatus.UNAUTHORIZED.value(), "认è¯å¤±è´¥è¯·éæ°ç»å½", null);
String json = JSON.toJSONString(result) ;
WebUtils.renderString(response,json);
}
}
4.5.2 ææ失败å¤çå¨
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
ResponseResult result = new ResponseResult(HttpStatus.FORBIDDEN.value(), "æéä¸è¶³" , null);
String json = JSON.toJSONString(result);
WebUtils.renderString(response,json);
}
}
4.5.3 Spring Securityé ç½®å¤çå¨
å®ç°æ¥éª¤ï¼
1ãå æ³¨å ¥å¯¹åºçå¤çå¨
2ã使ç¨HttpSecurity对象çæ¹æ³å»é ç½®
5 è·¨åå¤ç
5.1 è·¨å说æ
æµè§å¨åºäºå®å ¨çèèï¼ä½¿ç¨ XMLHttpRequest对象åèµ· HTTP请æ±æ¶å¿ é¡»éµå®åæºçç¥ï¼å¦åå°±æ¯è·¨åçHTTP请æ±ï¼é»è®¤æ åµä¸æ¯è¢«ç¦æ¢çã
åæºçç¥è¦æ±æºç¸åæè½æ£å¸¸è¿è¡éä¿¡ï¼æè°çæºç¸åæå®æ¯ï¼åè®®ãååã端å£å·é½å®å ¨ä¸è´ã
åå端å离项ç®ï¼å端项ç®åå端项ç®ä¸è¬é½ä¸æ¯åæºçï¼æ以è¯å®ä¼åå¨è·¨å请æ±çé®é¢ã
æ以æ们就è¦å¤çä¸ä¸ï¼è®©å端è½è¿è¡è·¨å请æ±ã
5.2 解å³æ¹æ¡
5.2.1 Spring Boot项ç®æ·»å è·¨å请æ±é ç½®
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置å
许跨åçè·¯å¾
registry.addMapping("/**")
// 设置å
许跨å请æ±çåå
.allowedOriginPatterns("*")
// æ¯å¦å
许cookie
.allowCredentials(true)
// 设置å
许ç请æ±æ¹å¼
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置å
许çheaderå±æ§
.allowedHeaders("*")
// è·¨åå
许æ¶é´
.maxAge(3600);
}
}
5.2.2 Spring Securityå¼å¯è·¨å访é®æ¯æ
ç±äºæ们çèµæºé½ä¼æ¶å°Spring Securityçä¿æ¤ï¼æ以æ³è¦è·¨å访é®è¿è¦è®©Spring Securityè¿è¡è·¨å访é®ã
//SpringSecurityConfigurer#configure å
许跨å
http.cors();
6 å ¶ä»é®é¢è¯´æ
6.1 å ¶ä»æéæ ¡éªæ¹å¼
æ们åé¢é½æ¯ä½¿ç¨@PreAuthorize注解ï¼ç¶åå¨å¨å ¶ä¸ä½¿ç¨çæ¯hasAuthorityæ¹æ³è¿è¡æ ¡éªãSpring Securityè¿ä¸ºæ们æä¾äºå ¶å®æ¹æ³ä¾å¦ï¼hasAnyAuthorityï¼hasRoleï¼
hasAnyRoleçã
6.1.2 hasAnyAuthority
hasAnyAuthorityæ¹æ³å¯ä»¥ä¼ å ¥å¤ä¸ªæéï¼åªæç¨æ·æå ¶ä¸ä»»æä¸ä¸ªæéé½å¯ä»¥è®¿é®å¯¹åºèµæºã
6.1.3 hasRole
hasRoleè¦æ±æ对åºçè§è²æå¯ä»¥è®¿é®ï¼ä½æ¯å®å é¨ä¼ææä»¬ä¼ å ¥çåæ°æ¼æ¥ä¸ ROLE_ ååå»æ¯è¾ãæ以è¿ç§æ åµä¸è¦ç¨ç¨æ·å¯¹åºçæéä¹è¦æ ROLE_ è¿ä¸ªåç¼æå¯ä»¥ã
6.1.4 hasAnyRole
hasAnyRole æä»»æçè§è²å°±å¯ä»¥è®¿é®ãå®å é¨ä¹ä¼ææä»¬ä¼ å ¥çåæ°æ¼æ¥ä¸ ROLE_ ååå»æ¯è¾ãæ以è¿ç§æ åµä¸è¦ç¨ç¨æ·å¯¹åºçæéä¹è¦æ ROLE_ è¿ä¸ªåç¼æå¯ä»¥ã
6.2 åºäºé ç½®çæéæ§å¶
æ们ä¹å¯ä»¥å¨é 置类ä¸ä½¿ç¨ä½¿ç¨é ç½®çæ¹å¼å¯¹èµæºè¿è¡æéæ§å¶ã
注æï¼ å¦ææ¤æ¶å¨æ¹æ³ä¸ä½¿ç¨äº@PreAuthorize(value = "hasAuthority('system:user:add')")æå®äºæéä¿¡æ¯ï¼é£ä¹å°±éè¦ç¨äºåæ¶æ¥æ两个æéæå¯ä»¥è¿è¡è®¿é®ã
6.3 CSRF
CSRFæ¯æè·¨ç«è¯·æ±ä¼ªé ï¼Cross-site request forgeryï¼ï¼æ¯web常è§çæ»å»ä¹ä¸ãhttps://blog.csdn.net/freeking101/article/details/86537087
Spring Securityå»é²æ¢CSRFæ»å»çæ¹å¼å°±æ¯éè¿csrf_tokenãå端ä¼çæä¸ä¸ªcsrf_tokenï¼å端å起请æ±çæ¶åéè¦æºå¸¦è¿ä¸ªcsrf_token,å端ä¼æè¿æ»¤å¨è¿è¡æ ¡éªï¼å¦æ没ææº
带æè æ¯ä¼ªé çå°±ä¸å 许访é®ã
æ们å¯ä»¥åç°CSRFæ»å»ä¾é çæ¯cookieä¸ææºå¸¦ç认è¯ä¿¡æ¯ãä½æ¯å¨åå端å离ç项ç®ä¸æ们ç认è¯ä¿¡æ¯å ¶å®æ¯tokenï¼ètoken并ä¸æ¯åå¨å¨cookieä¸ï¼å¹¶ä¸éè¦å端代ç å»æ
token设置å°è¯·æ±å¤´ä¸æå¯ä»¥ï¼æ以CSRFæ»å»ä¹å°±ä¸ç¨æ å¿äºã
7 æ»ç»
æ¬æç« ç»å¤§å®¶ä»ç»äºä¸ä¸å¨åå端å离项ç®ä¸å¦ä½ä½¿ç¨Spring Securityå®æ认è¯åææçç¸å ³æä½ï¼å¹¶ä¸ä»ç»ä¸ä¸å¦ä½èªå®ä¹è®¤è¯åææ失败çå¤çå¨ï¼ä»¥åå¦ä½è§£å³è·¨åçç¸å ³
é®é¢ã大家å¯ä»¥åèæ¬æç« å®é æä½ä¸ä¸ï¼ç¸ä¿¡å¤§å®¶å¾å¿«å°±å¯ä»¥ææ¡Spring Securityå¨åå端å离项ç®ä¸ç使ç¨ã