Skip to main content
 首页 » 编程设计

spring-security之独立 Spring OAuth2 JWT 授权服务器 + CORS

2024年11月24日43freeliver54

所以我有以下从 this example 浓缩的授权服务器来自戴夫·赛尔

@SpringBootApplication 
public class AuthserverApplication { 
 
    public static void main(String[] args) { 
            SpringApplication.run(AuthserverApplication.class, args); 
    } 
 
    /* added later 
    @Configuration 
    @Order(Ordered.HIGHEST_PRECEDENCE) 
    protected static class MyWebSecurity extends WebSecurityConfigurerAdapter { 
 
        @Override 
        protected void configure(HttpSecurity http) throws Exception { 
            http //.csrf().disable()  
                .authorizeRequests() 
                .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll(); 
       } 
    }*/ 
 
    @Configuration 
    @EnableAuthorizationServer 
    protected static class OAuth2AuthorizationConfig extends 
                    AuthorizationServerConfigurerAdapter { 
 
            @Autowired 
            private AuthenticationManager authenticationManager; 
 
            @Bean 
            public JwtAccessTokenConverter jwtAccessTokenConverter() { 
                    JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 
                    KeyPair keyPair = new KeyStoreKeyFactory( 
                                    new ClassPathResource("keystore.jks"), "foobar".toCharArray()) 
                                    .getKeyPair("test"); 
                    converter.setKeyPair(keyPair); 
                    return converter; 
            } 
 
            @Override 
            public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 
                    clients.inMemory() 
                                    .withClient("acme") 
                                    //.secret("acmesecret") 
                                    .authorizedGrantTypes(//"authorization_code", "refresh_token", 
                                                    "password").scopes("openid"); 
            } 
 
            @Override 
            public void configure(AuthorizationServerEndpointsConfigurer endpoints) 
                            throws Exception { 
                    endpoints.authenticationManager(authenticationManager).accessTokenConverter( 
                                    jwtAccessTokenConverter()); 
            } 
 
            @Override 
            public void configure(AuthorizationServerSecurityConfigurer oauthServer) 
                            throws Exception { 
                    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess( 
                                    "isAuthenticated()"); 
            } 
    } 
} 

当我运行它并用 curl 测试它时
curl acme@localhost:8110/oauth/token -d grant_type=password -d client_id=acme -d username=user -d password=password 

我得到一个 JWT 作为响应,但是当我尝试从我的前端(不同端口上的 Angular JS)访问 AuthServer 时,我得到了 CORS 错误。不是因为缺少 header ,而是因为 OPTION 请求被拒绝并且缺少凭据。
Request URL:http://localhost:8110/oauth/token 
Request Method:OPTIONS 
Status Code:401 Unauthorized 
WWW-Authenticate:Bearer realm="oauth", error="unauthorized", error_description="Full authentication is required to access this resource" 

我已经知道我必须添加一个 CorsFilter 并且另外发现了 this post我使用第一个答案的片段来让 OPTIONS 请求访问 /oauth/token没有凭据:

@Order(-1) 
public class MyWebSecurity extends WebSecurityConfigurerAdapter { 
   @Override 
   protected void configure(HttpSecurity http) throws Exception { 
       http 
          .authorizeRequests() 
          .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll(); 
   } 
} 

之后,我得到了 curl 以下错误:
{"timestamp":1433370068120,"status":403,"error":"Forbidden","message":"Expected CSRF token not found. Has your session expired?","path":"/oauth/token"} 

所以为了简单起见,我只是添加了 http.csrf().disable()configure MyWebSecurity 类的方法,它解决了 OPTION 请求的问题,但因此 POST 请求不再工作,我得到 There is no client authentication. Try adding an appropriate authentication filter. (也有 curl )。

我试图找出是否必须以某种方式连接 MyWebSecurity 类和 AuthServer,但没有任何运气。原始示例(开头的链接)也注入(inject)了 authenticationManager,但这对我来说没有任何改变。

请您参考如下方法:

找到了我的问题的原因!

如果 CorsFilter 处理了 OPTIONS 请求,我只需要结束过滤器链并立即返回结果!

SimpleCorsFilter.java

@Component 
@Order(Ordered.HIGHEST_PRECEDENCE) 
public class SimpleCorsFilter implements Filter { 
 
    public SimpleCorsFilter() { 
    } 
 
    @Override 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
        HttpServletResponse response = (HttpServletResponse) res; 
        HttpServletRequest request = (HttpServletRequest) req; 
        response.setHeader("Access-Control-Allow-Origin", "*"); 
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); 
        response.setHeader("Access-Control-Max-Age", "3600"); 
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization"); 
 
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { 
            response.setStatus(HttpServletResponse.SC_OK); 
        } else { 
            chain.doFilter(req, res); 
        } 
    } 
 
    @Override 
    public void init(FilterConfig filterConfig) { 
    } 
 
    @Override 
    public void destroy() { 
    } 
} 

之后,我可以忽略 AuthServer =D 中的 OPTIONS 预检请求

所以服务器就像上面的截图一样工作,你可以在开始时忽略 MyWebSecurity 类的 block 注释。