Spring Security Authentication By User - PullRequest
       8

Spring Security Authentication By User

0 голосов
/ 22 апреля 2020

Я занимаюсь разработкой базового c приложения для заметок с пружинной загрузкой. Когда GET-запрос приходит к NoteController, я хочу проверить, есть ли у пользователя эта заметка. В примере обратите внимание, что идентификатор 1 принадлежит UserA. Если UserB попытается получить эту заметку, введя этот URL: / note / 1, я не хочу, чтобы UserB получил доступ к этой заметке. Чтобы решить эту проблему, каждый раз, когда к NoteController приходит запрос, я получаю аутентифицированного пользователя из SecurityContextHolder и проверяю, принадлежит ли заметка этому пользователю. Есть ли что-нибудь лучше, чем это?

NoteController

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);
    }
}

WebSecurityConfig

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);
    }
}

1 Ответ

0 голосов
/ 22 апреля 2020

Все результаты вызова findById() предоставляются для проверки полномочий, что означает, что лог c может быть перемещен в общее место, то есть findById().

Те же логины авторизации c можно выполнить с помощью Выражения безопасности метода : @ PostAuthorize аннотация

Пример может быть следующим. NoteService.findById(id) метод может быть изменен, чтобы иметь эту проверку, и пользовательский лог проверки c из методов контроллера может быть удален.

@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 {
//...
}

Надеюсь, это поможет.

...