Вход в Spring с помощью JWT WebSecurityConfigAdapter настроить авторизацию метода не работает - PullRequest
0 голосов
/ 27 ноября 2018

Так что я пытаюсь сделать логин отдыхающим, и все идет хорошо, ожидая одного.После успешного входа в систему и пользователь имеет доступ к ссылкам, которые не должны иметь.Я предполагаю, что есть что-то плохое в методе "configure" в классе extends WebSecurityConfigurerAdapter, потому что hasAuthority не работает должным образом.Пожалуйста, ребята, просмотрите мой код и скажите, как он должен выглядеть.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class Security extends WebSecurityConfigurerAdapter {

    private final Provider provider;
    private final EntryPoint entryPoint;
    private final CorsFilter corsFilter;

    @Autowired
    public Security(Provider provider, EntryPoint entryPoint, CorsFilter corsFilter) {
        this.provider = provider;
        this.entryPoint = entryPoint;
        this.corsFilter = corsFilter;
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        return bCryptPasswordEncoder;
    }
    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(Collections.singletonList(provider));
    }
    public AuthenticationTokenFilter authenticationTokenFilter() {
        AuthenticationTokenFilter filter = new AuthenticationTokenFilter();
        filter.setAuthenticationManager(authenticationManager());
        filter.setAuthenticationSuccessHandler(new SuccessHandler());
        return filter;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        String roleAdmin = "Admin";
        http.authorizeRequests()
                .antMatchers("/api/**").authenticated()
                .antMatchers(HttpMethod.GET, "/api/office").hasAnyAuthority()
                .antMatchers(HttpMethod.GET, "/user").hasAnyAuthority()
                .antMatchers(HttpMethod.GET, "/userDetails/**").hasAnyAuthority()
                .antMatchers("/api/office/admin").hasAuthority(roleAdmin)
                .antMatchers("/api/office/user").hasAuthority(roleAdmin)
                .antMatchers("/api/office/roleadmin").hasRole(roleAdmin)
                .antMatchers("/api/office/roleuser").hasRole(roleAdmin)
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint(entryPoint)
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterBefore(corsFilter, ChannelProcessingFilter.class)
                .addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)
                .headers()
                .cacheControl();
    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        web
                .ignoring()
                .antMatchers("/login");
    }
}

Класс CorsFilter

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    public CorsFilter() {
        super();
    }

    @Override
    public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
        final HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        // without this header jquery.ajax calls returns 401 even after successful login and session being successfully stored.
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Authorization, Origin, Content-Type, Version");
        response.setHeader("Access-Control-Expose-Headers", "X-Requested-With, Authorization, Origin, Content-Type");

        final HttpServletRequest request = (HttpServletRequest) servletRequest;
        if (!request.getMethod().equals("OPTIONS")) {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

Дополнительный класс фильтра токенов

public class AuthenticationTokenFilter extends AbstractAuthenticationProcessingFilter {

    public AuthenticationTokenFilter() {
        super("/api/**");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        String header = request.getHeader(SecurityClaims.HEADER);
        if (header == null || !header.startsWith(SecurityClaims.TOKEN_PREFIX)) {
            throw new RuntimeException(SecurityClaims.TOKEN_MISSING);
        }
        String authenticationToken = header.substring(SecurityClaims.SUB_PREFIX);
        AuthenticationToken token = new AuthenticationToken(authenticationToken);
        return getAuthenticationManager().authenticate(token);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        super.successfulAuthentication(request, response, chain, authResult);
        chain.doFilter(request, response);
    }
}

Контроллер для теста

@CrossOrigin
@RestController
@RequestMapping("/api/office")
public class OfficeController {
    private final OfficeService officeService;
    @Autowired
    public OfficeController(OfficeService officeService) {
        this.officeService = officeService;
    }
    @GetMapping("/admin")
    public @ResponseBody
    String adminek() {
        return "for authority admin";
    }
    @GetMapping("/user")
    public @ResponseBody
    String userek() {
        return "for authority user";
    }
    @GetMapping("/roleadmin")
    public @ResponseBody
    String roleadmin() {
        return "for role admin";
    }
    @GetMapping("/roleuser")
    public @ResponseBody
    String roleuser() {
        return "for role user";
    }
}

Точка входа

@Component
public class EntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, SecurityClaims.MESSAGE);
    }
}

1 Ответ

0 голосов
/ 28 ноября 2018

Дело в том, что в классе Security расширяется метод WebSecurityConfigurerAdapter, в котором сконфигурировано значение

.antMatchers("/api/office/admin").hasAuthority(roleAdmin)
.antMatchers("/api/office/user").hasAuthority(roleAdmin)
.antMatchers("/api/office/roleadmin").hasRole(roleAdmin)
.antMatchers("/api/office/roleuser").hasRole(roleAdmin)

, и оно не должно иметь их (потому что Spring не будет беспокоиться об этом).Этот метод должен выглядеть следующим образом:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/**").authenticated()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint(entryPoint)
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(corsFilter, ChannelProcessingFilter.class)
                .headers()
                .cacheControl();
    }

И каждый метод контроллера должен иметь свою собственную аннотацию безопасности:

@GetMapping
    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
    public @ResponseBody
    PageToView findAll(@RequestParam(required = false) String value, Pageable pageable) {
        return officeService.findAll(value, pageable);
    }

Согласно https://www.baeldung.com/spring-security-method-security и Can SpringБезопасность использует @PreAuthorize для методов контроллеров Spring? Помните, как правильно назвать роль: ROLE_EXAMPLE https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#el-common-built-in

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...