代码之家  ›  专栏  ›  技术社区  ›  Igor

仅在需要身份验证时应用spring安全筛选器(由我的应用程序)

  •  0
  • Igor  · 技术社区  · 5 年前

    我读过 How to apply spring security filter only on secured endpoints?

    下面您将看到我当前使用的WebSecurity配置适配器配置。它不会一直保持这样,因为我以后不会公开h2控制台。

    JwtAuthenticationFilter 总是执行。我更希望在需要身份验证的请求上执行过滤器(在我的特定情况下:仅此处所述:

    .authorizeRequests()
                    .anyRequest()
                        .authenticated()
    

    ).

    如何做到这一点?

    io.jsonwebtoken.SignatureException ,因为JWTH2控制台生成和使用的内容与我的应用程序使用的内容自然不同。

    Web安全配置适配器 :

    package com.particles.authservice;
    
    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.BeanIds;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    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.web.authentication.UsernamePasswordAuthenticationFilter;
    
    import com.particles.authservice.jwt.JwtAuthenticationEntryPoint;
    import com.particles.authservice.jwt.JwtAuthenticationFilter;
    import com.particles.authservice.service.UserService;
    
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserService userService;
    
        @Autowired
        private JwtAuthenticationEntryPoint unauthorizedHandler;
    
        @Override
        public void configure(final AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
            authenticationManagerBuilder
                                        .userDetailsService(userService)
                                        .passwordEncoder(passwordEncoder());
        }
    
        @Override
        protected void configure(final HttpSecurity http) throws Exception {
            //@formatter:off
            http
                .cors()
                    .and()
                .csrf()
                    .disable()
                .headers()
                    .frameOptions()
                        .disable()
                        .and()
                .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                .authorizeRequests()
                    .antMatchers("/",
                            "/favicon.ico",
                            "/**/*.png",
                            "/**/*.gif",
                            "/**/*.svg",
                            "/**/*.jpg",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js")
                        .permitAll()
                    .antMatchers("/h2-console/**").permitAll()
                    .antMatchers(HttpMethod.POST, "/register")
                        .permitAll()
                    .antMatchers(HttpMethod.GET, "/confirm")
                        .permitAll()
                    .antMatchers(HttpMethod.POST, "/login")
                        .permitAll()
                    .antMatchers(HttpMethod.GET, "/user")
                        .permitAll()
                    .and()
                .authorizeRequests()
                    .anyRequest()
                        .authenticated()
                    .and()
                .exceptionHandling()
                    .authenticationEntryPoint(unauthorizedHandler)
                    .and()
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                ;
            //@formatter:on
        }
    
        @Bean(BeanIds.AUTHENTICATION_MANAGER)
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Bean
        public JwtAuthenticationFilter jwtAuthenticationFilter() {
            return new JwtAuthenticationFilter();
        }
    
        @Bean
        public BCryptPasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
    

    编辑: 这是JwtAuthenticationFilter。如果你也需要TOs,请告诉我。

    :

    package com.particles.authservice.jwt;
    
    import java.io.IOException;
    import java.util.Optional;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
    import org.springframework.util.StringUtils;
    import org.springframework.web.filter.OncePerRequestFilter;
    
    import com.particles.authservice.tos.UserJwt;
    
    public class JwtAuthenticationFilter extends OncePerRequestFilter {
        private static final String AUTHORIZATION_HEADER_PREFIX               = "Authorization";
        private static final String AUTHORIZATION_HEADER_BEARER_PREFIX        = "Bearer ";
        private static final int    AUTHORIZATION_HEADER_BEARER_PREFIX_LENGTH = AUTHORIZATION_HEADER_BEARER_PREFIX.length();
    
        @Autowired
        private JwtService jwtService;
    
        @Override
        protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
                throws ServletException, IOException {
            if (request.getHeader(AUTHORIZATION_HEADER_PREFIX) != null) {
                final Optional<String> optToken = extractTokenFromRequest(request);
    
                if (optToken.isPresent() && StringUtils.hasText(optToken.get()) && jwtService.isTokenValid(optToken.get())) {
                    // if token exists and is valid, retrieve corresponding UserJwt-object
                    final UserJwt jwt = jwtService.getJwtFromToken(optToken.get());
    
                    final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(jwt.getUser(), null,
                            jwt.getUser().getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
    
            filterChain.doFilter(request, response);
        }
    
        /**
         * This method extracts a JWT from a {@link HttpServletRequest}-object.
         *
         * @param request
         *            ({@link HttpServletRequest}) request, which supposedly contains a JWT
         * @return (Optional&lt;String&gt;) JWT as String
         */
        private Optional<String> extractTokenFromRequest(final HttpServletRequest request) {
            final String bearerToken = request.getHeader(AUTHORIZATION_HEADER_PREFIX);
    
            String bearerTokenContent = null;
            if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(AUTHORIZATION_HEADER_BEARER_PREFIX)) {
                bearerTokenContent = bearerToken.substring(AUTHORIZATION_HEADER_BEARER_PREFIX_LENGTH, bearerToken.length());
            }
    
            return Optional.ofNullable(bearerTokenContent);
        }
    }
    

    如果您需要查看任何其他类,请告诉我,我会将它们粘贴到这里。

    0 回复  |  直到 5 年前
        1
  •  0
  •   Thirumal    5 年前

    添加以下方法以公开公共端点

     @Override
     public void configure(WebSecurity web) throws Exception {
        web.ignoring()
        .antMatchers("/public-api/**");
      }
    
        2
  •  0
  •   Igor    5 年前

    WebSecurityConfigurerAdapter#configure 方法

    相反,我决定将私有API中的端点与所有其他端点分开。

    • 端点,需要过滤器(在我的例子中 JwtAuthenticationFilter /api/ 而且没有单独定义,因为很有可能有人忘记将它们添加到 configure -方法
    • /原料药/

    我的配置方法如下所示:

    @Override
        protected void configure(final HttpSecurity http) throws Exception {
            //@formatter:off
            http
                .cors()
                    .and()
                .csrf()
                    .disable()
                .headers()
                    .frameOptions()
                        .disable()
                        .and()
                .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                .authorizeRequests()
                    .antMatchers("/",
                            "/favicon.ico",
                            "/**/*.png",
                            "/**/*.gif",
                            "/**/*.svg",
                            "/**/*.jpg",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js")
                        .permitAll()
                    .antMatchers("/h2-console/**").permitAll()
                    .antMatchers(HttpMethod.POST,
                            PUBLIC_API_PATH + "register",
                            PUBLIC_API_PATH + "login")
                        .permitAll()
                    .antMatchers(HttpMethod.GET,
                            PUBLIC_API_PATH + "confirm")
                        .permitAll()
                    .and()
                .authorizeRequests()
                    .anyRequest()
                        .authenticated()
                    .and()
                .exceptionHandling()
                    .authenticationEntryPoint(unauthorizedHandler)
                    .accessDeniedHandler(unauthorizedHandler)
                    .and()
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                ;
            //@formatter:on
    

    JwtAuthenticationFilter 我检查请求路径是否包含私有API路径 /原料药/ . 我只应用过滤,如果它这样做。

        @Override
        protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
                throws ServletException, IOException {
            if (request.getRequestURI().contains(SecurityConfiguration.PRIVATE_API_PATH)) {
                // perform Jwt-authentication since request-URI suggests a call to private-API
    ...
                }
            }
    
            filterChain.doFilter(request, response);
        }
    

    我不喜欢这个解决方案,尤其是因为我必须保持 SecurityConfiguration.PRIVATE_API_PATH

    如果你有更好的建议,我很想试试。

    编辑 @PostMapping(value = "${apipath}/user") . 因此,我可以使路径毕竟是可配置的-但签入 尽管如此,我们必须保持沉默;我只是不需要使用常量,而是使用变量,其中包含来自。 application.yaml .