java - 用户的 Spring Security 身份验证
问题描述
我正在使用 Spring Boot 开发一个基本的笔记应用程序。当一个 GET 请求来到 NoteController 时,我想检查用户是否有这个注释。在示例注释中,id 为 1 的属于 UserA 。如果 UserB 尝试通过此 url 获取此便笺:/note/1,我不希望 UserB 访问此便笺。为了解决这个问题,每次向 NoteController 发出请求时,我都会从 SecurityContextHolder 获取经过身份验证的用户,并检查便笺是否属于该用户。还有什么比这更好的吗?
笔记控制器
package app.controller;
import app.entity.Note;
import app.entity.User;
import app.service.NoteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/note")
public class NoteController
{
@Autowired
private NoteService noteService;
@PostMapping
public Note save(@RequestBody Note note)
{
User user=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
note.setUser(user);
noteService.save(note);
return note;
}
@PutMapping
public ResponseEntity<Void> update(@RequestBody Note note)
{
User user=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if(noteService.findById(note.getId()).getUser().getId()==user.getId())
{
noteService.update(note);
return new ResponseEntity<>(HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
@GetMapping("/{id}")
public ResponseEntity<Note> findById(@PathVariable int id)
{
User user=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Note note=noteService.findById(id);
if(note.getUser().getId()==user.getId())
return new ResponseEntity<>(note,HttpStatus.OK);
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
@GetMapping
public List<Note> findByUser()
{
User user=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return noteService.findByUser(user);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteById(@PathVariable int id)
{
User user=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Note note=noteService.findById(id);
if(note.getUser().getId()==user.getId())
{
noteService.deleteById(id);
return new ResponseEntity<>(HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
网络安全配置
package app.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
private TokenFilter tokenFilter;
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers(HttpMethod.POST,"/note").hasAuthority("CREATE")
.antMatchers(HttpMethod.GET,"/note").hasAuthority("READ")
.antMatchers(HttpMethod.PUT,"/note").hasAuthority("UPDATE")
.antMatchers(HttpMethod.DELETE,"/note").hasAuthority("DELETE")
.anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(tokenFilter,UsernamePasswordAuthenticationFilter.class);
}
}
解决方案
所有的findById()
调用结果都给出了授权检查,这意味着逻辑可以移动到一个共同的地方,即findById()
。
可以使用方法安全表达式完成相同的授权逻辑:@PostAuthorize注释
一个例子如下。NoteService.findById(id)
可以修改方法以进行此检查,并且可以删除控制器方法中的用户检查逻辑。
@PostAuthorize("returnObject.user.id == principal.id")
public Note findById(Long id)
{
return noteRepository.findById(id);
}
这里@PostAuthorize
是在内置的returnObject
.
还要记住如下启用 GlobalMethodSecurity 以使 Pre 和 Post 注释工作
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
//...
}
希望这可以帮助。
推荐阅读
- shell - Shell:如何正确确定文件是否包含一个或多个空字符?
- sql-server - 将数据类型 nvarchar 转换为数字时出错 - 排序规则
- r - 如何在R中绘制美国多个州的轮廓?
- docker - Docker统计内存异常
- c# - Extracting substring based on the same identifier in two locations
- javascript - 如何使用 Amazon Cognito 托管的 Web UI 获取用户参数
- python-3.x - Bringing other Chef cookbooks into a custom cookbook
- php - 如何在 macos high sierra 上使用 homebrew 或 pecl 在 php 7.0 上安装 php-redis?
- django - 注册页面即时缓冲
- r - How to extract edge attributes from a directed graph shortest path: