Spring Security OAuth2 permitAll() 方法小记

2022-08-23 11:55:27

1. 前言

在使用spring-security-oauth2时,虽然配置了.antMatchers("/permitAll").permitAll(),但如果在header 中 携带Authorization Bearer xxxxOAuth2AuthenticationProcessingFilter还是会去校验Token的正确性,如果Token合法,可以正常访问,否则,请求失败。他的需求是当配置.permitAll()时,即使携带Token,也可以直接访问。

2. 解决思路

根据Spring Security源码分析一:Spring Security认证过程得知spring-security的认证为一系列过滤器链。我们只需定义一个比OAuth2AuthenticationProcessingFilter更早的过滤器拦截指定请求,去除header中的Authorization Bearer xxxx即可。

3. 代码修改

3.1 添加PermitAuthenticationFilter类

添加PermitAuthenticationFilter类拦截指定请求,清空header中的Authorization Bearer xxxx

@Component("permitAuthenticationFilter")
@Slf4j
public class PermitAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        log.info("当前访问的地址:{}", request.getRequestURI());
        if ("/permitAll".equals(request.getRequestURI())) {

            request = new HttpServletRequestWrapper(request) {
                private Set<String> headerNameSet;

                @Override
                public Enumeration<String> getHeaderNames() {
                    if (headerNameSet == null) {
                        // first time this method is called, cache the wrapped request's header names:
                        headerNameSet = new HashSet<>();
                        Enumeration<String> wrappedHeaderNames = super.getHeaderNames();
                        while (wrappedHeaderNames.hasMoreElements()) {
                            String headerName = wrappedHeaderNames.nextElement();
                            if (!"Authorization".equalsIgnoreCase(headerName)) {
                                headerNameSet.add(headerName);
                            }
                        }
                    }
                    return Collections.enumeration(headerNameSet);
                }

                @Override
                public Enumeration<String> getHeaders(String name) {
                    if ("Authorization".equalsIgnoreCase(name)) {
                        return Collections.<String>emptyEnumeration();
                    }
                    return super.getHeaders(name);
                }

                @Override
                public String getHeader(String name) {
                    if ("Authorization".equalsIgnoreCase(name)) {
                        return null;
                    }
                    return super.getHeader(name);
                }
            };

        }
        filterChain.doFilter(request, response);

    }
}

3.2 添加PermitAllSecurityConfig配置

添加PermitAllSecurityConfig配置用于配置PermitAuthenticationFilter

@Component("permitAllSecurityConfig")
public class PermitAllSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,HttpSecurity> {

    @Autowired
    private Filter permitAuthenticationFilter;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(permitAuthenticationFilter, OAuth2AuthenticationProcessingFilter.class);
    }
}

3.3 修改MerryyouResourceServerConfig,增加对制定路径的授权

@Override
   public void configure(HttpSecurity http) throws Exception {

       // @formatter:off
       http.formLogin()
               .successHandler(appLoginInSuccessHandler)//登录成功处理器
               .and()
               .apply(permitAllSecurityConfig)
               .and()
               .authorizeRequests()
               .antMatchers("/user").hasRole("USER")
               .antMatchers("/forbidden").hasRole("ADMIN")
               .antMatchers("/permitAll").permitAll()
               .anyRequest().authenticated().and()
               .csrf().disable();

       // @formatter:ON
   }

3.4 修改测试类SecurityOauth2Test

添加permitAllWithTokenTest方法

@Test
public void permitAllWithTokenTest() throws Exception{
    final String accessToken = obtainAccessToken();
    log.info("access_token={}", accessToken);
    String content = mockMvc.perform(get("/permitAll").header("Authorization", "bearer " + accessToken+"11"))
            .andExpect(status().isOk())
            .andReturn().getResponse().getContentAsString();
    log.info(content);
}
  • Authorization bearer xxx 11后面随机跟了两个参数

3.5 效果如下

3.5.1 不配置permitAllSecurityConfig时

3.5.2 配置permitAllSecurityConfig时

4. 代码下载

  • 作者:weixin_42073629
  • 原文链接:https://blog.csdn.net/weixin_42073629/article/details/106485722
    更新时间:2022-08-23 11:55:27