gpt4 book ai didi

Spring Security OAuth2 在没有 JWT 的情况下无法工作

转载 作者:行者123 更新时间:2023-12-02 06:46:41 29 4
gpt4 key购买 nike

我正在尝试实现 Spring Security and Angular JS 中的 OAuth2 示例教程,但我在没有 JWT 的情况下使其工作时遇到问题。该示例的代码可以找到 here .

我对示例进行了以下修改,以尝试使其在没有 JWT 的情况下正常工作。

/resource/src/main/resources/application.properties

server.port: 9998
server.contextPath: /resource
logging.level.org.springframework.security: DEBUG
#spring.oauth2.resource.jwt.keyValue: -----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnGp/Q5lh0P8nPL21oMMrt2RrkT9AW5jgYwLfSUnJVc9G6uR3cXRRDCjHqWU5WYwivcF180A6CWp/ireQFFBNowgc5XaA0kPpzEtgsA5YsNX7iSnUibB004iBTfU9hZ2Rbsc8cWqynT0RyN4TP1RYVSeVKvMQk4GT1r7JCEC+TNu1ELmbNwMQyzKjsfBXyIOCFU/E94ktvsTZUHF4Oq44DBylCDsS1k7/sfZC2G5EU7Oz0mhG8+Uz6MSEQHtoIi6mc8u64Rwi3Z3tscuWG2ShtsUFuNSAFNkY7LkLn+/hxLCu2bNISMaESa8dG22CIMuIeRLVcAmEWEWH5EEforTg+QIDAQAB\n-----END PUBLIC KEY-----

注释掉了 jwt keyValue 的属性。

/ui/src/main/resources/application.yml

security:
user:
password: none
oauth2:
client:
accessTokenUri: http://localhost:9999/uaa/oauth/token
userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize
clientId: acme
clientSecret: acmesecret
resource:
userInfoUri: http://localhost:9999/uaa/user
# jwt:
# keyValue: |
# -----BEGIN PUBLIC KEY-----
# #MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnGp/Q5lh0P8nPL21oMMrt2RrkT9AW5jgYwLfSUnJVc9G6uR3cXRRDCjHqWU5WYwivcF180A6CWp/ireQFFBNowgc5XaA0kPpzEtgsA5YsNX7iSnUibB004iBTfU9hZ2Rbsc8cWqynT0RyN4TP1RYVSeVKvMQk4GT1r7JCEC+TNu1ELmbNwMQyzKjsfBXyIOCFU/E94ktvsTZUHF4Oq44DBylCDsS1k7/sfZC2G5EU7Oz0mhG8+Uz6MSEQHtoIi6mc8u64Rwi3Z3tscuWG2ShtsUFuNSAFNkY7LkLn+/hxLCu2bNISMaESa8dG22CIMuIeRLVcAmEWEWH5EEforTg+QIDAQAB
# -----END PUBLIC KEY-----
zuul:
routes:
resource:
path: /resource/**
url: http://localhost:9000/resource
user:
path: /user/**
url: http://localhost:9999/uaa/user

logging:
level:
org.springframework.security: DEBUG

注释掉 jwt 属性并替换为:

userInfoUri: http://localhost:9999/uaa/user

/authserver/src/main/java/demo/AuthserverApplication.java

@SpringBootApplication
@Controller
@SessionAttributes("authorizationRequest")
@EnableResourceServer
public class AuthserverApplication extends WebMvcConfigurerAdapter {

@RequestMapping("/user")
@ResponseBody
public Principal user(Principal user) {
return user;
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/oauth/confirm_access").setViewName("authorize");
}

public static void main(String[] args) {
SpringApplication.run(AuthserverApplication.class, args);
}

@Configuration
@Order(-20)
protected static class LoginConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AuthenticationManager authenticationManager;

@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.formLogin().loginPage("/login").permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests().anyRequest().authenticated();
// @formatter:on
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager);
}
}

@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()");
}

}
}

注释掉 jwtAccessTokenConverter() 方法并将其从 configure(AuthorizationServerEndpointsConfigurer endpoints) 中删除。

当我尝试运行该应用程序时,它工作正常,直到我必须授权“acme”访问 protected 资源。当我单击“批准”时,我收到 401 和错误页面,显示“身份验证失败:无法获取访问 token ”。

这是由对 http://localhost:9999/uaa/oauth/authorize 的 POST 请求引起的失败然后重定向到 http://localhost:8080/login?error=access_denied&error_description=User%20denied%20access&state=lsb7Ik

以下是来自 API 网关和 OAuth2 服务器的以下日志。

API网关应用

2015-11-19 12:04:24.561 DEBUG 41956 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy        : /login?error=access_denied&error_description=User%20denied%20access&state=ksNKYy at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-11-19 12:04:24.561 DEBUG 41956 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy : /login?error=access_denied&error_description=User%20denied%20access&state=ksNKYy at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-11-19 12:04:24.561 DEBUG 41956 --- [nio-8080-exec-6] w.c.HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2015-11-19 12:04:24.561 DEBUG 41956 --- [nio-8080-exec-6] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@6b29d520. A new one will be created.
2015-11-19 12:04:24.561 DEBUG 41956 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy : /login?error=access_denied&error_description=User%20denied%20access&state=ksNKYy at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-11-19 12:04:24.561 DEBUG 41956 --- [nio-8080-exec-6] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@24905eb7
2015-11-19 12:04:24.561 DEBUG 41956 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy : /login?error=access_denied&error_description=User%20denied%20access&state=ksNKYy at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2015-11-19 12:04:24.561 DEBUG 41956 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy : /login?error=access_denied&error_description=User%20denied%20access&state=ksNKYy at position 5 of 13 in additional filter chain; firing Filter: 'CsrfHeaderFilter'
2015-11-19 12:04:24.562 DEBUG 41956 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy : /login?error=access_denied&error_description=User%20denied%20access&state=ksNKYy at position 6 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
2015-11-19 12:04:24.562 DEBUG 41956 --- [nio-8080-exec-6] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/login'; against '/logout'
2015-11-19 12:04:24.562 DEBUG 41956 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy : /login?error=access_denied&error_description=User%20denied%20access&state=ksNKYy at position 7 of 13 in additional filter chain; firing Filter: 'OAuth2ClientAuthenticationProcessingFilter'
2015-11-19 12:04:24.562 DEBUG 41956 --- [nio-8080-exec-6] uth2ClientAuthenticationProcessingFilter : Request is to process authentication
2015-11-19 12:04:24.564 DEBUG 41956 --- [nio-8080-exec-6] g.c.AuthorizationCodeAccessTokenProvider : Encoding and sending form: {response_type=[code], client_id=[acme], scope=[null], state=[ksNKYy], redirect_uri=[http://localhost:8080/login]}
2015-11-19 12:04:24.571 WARN 41956 --- [nio-8080-exec-6] o.s.web.client.RestTemplate : POST request for "http://localhost:9999/uaa/oauth/authorize" resulted in 403 (Forbidden); invoking error handler
2015-11-19 12:04:24.575 DEBUG 41956 --- [nio-8080-exec-6] uth2ClientAuthenticationProcessingFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Could not obtain access token
2015-11-19 12:04:24.575 DEBUG 41956 --- [nio-8080-exec-6] uth2ClientAuthenticationProcessingFilter : Updated SecurityContextHolder to contain null Authentication
2015-11-19 12:04:24.575 DEBUG 41956 --- [nio-8080-exec-6] uth2ClientAuthenticationProcessingFilter : Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@489090b4
2015-11-19 12:04:24.575 DEBUG 41956 --- [nio-8080-exec-6] .a.SimpleUrlAuthenticationFailureHandler : No failure URL set, sending 401 Unauthorized error
2015-11-19 12:04:24.575 DEBUG 41956 --- [nio-8080-exec-6] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2015-11-19 12:04:24.575 DEBUG 41956 --- [nio-8080-exec-6] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2015-11-19 12:04:24.576 DEBUG 41956 --- [nio-8080-exec-6] o.s.b.a.e.mvc.EndpointHandlerMapping : Looking up handler method for path /error
2015-11-19 12:04:24.577 DEBUG 41956 --- [nio-8080-exec-6] o.s.b.a.e.mvc.EndpointHandlerMapping : Did not find handler method for [/error]

OAuth2 应用程序

2015-11-19 12:04:24.546 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/authorize at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-11-19 12:04:24.546 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-11-19 12:04:24.546 DEBUG 41954 --- [nio-9999-exec-2] w.c.HttpSessionSecurityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@fb75c5f1: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fb75c5f1: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@21a2c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 010CF170666FD7398D2E42E4431924B1; Granted Authorities: ROLE_ADMIN, ROLE_USER'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@335f832b
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/authorize'; against '/logout'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/authorize'; against '/login'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fb75c5f1: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@21a2c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 010CF170666FD7398D2E42E4431924B1; Granted Authorities: ROLE_ADMIN, ROLE_USER'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /oauth/authorize; Attributes: [authenticated]
2015-11-19 12:04:24.547 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fb75c5f1: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@21a2c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 010CF170666FD7398D2E42E4431924B1; Granted Authorities: ROLE_ADMIN, ROLE_USER
2015-11-19 12:04:24.548 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@54fdd60d, returned: 1
2015-11-19 12:04:24.548 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful
2015-11-19 12:04:24.548 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object
2015-11-19 12:04:24.548 DEBUG 41954 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /oauth/authorize reached end of additional filter chain; proceeding with original chain
2015-11-19 12:04:24.549 DEBUG 41954 --- [nio-9999-exec-2] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /oauth/authorize
2015-11-19 12:04:24.550 DEBUG 41954 --- [nio-9999-exec-2] .s.o.p.e.FrameworkEndpointHandlerMapping : Returning handler method [public org.springframework.web.servlet.View org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.approveOrDeny(java.util.Map<java.lang.String, java.lang.String>,java.util.Map<java.lang.String, ?>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)]
2015-11-19 12:04:24.552 DEBUG 41954 --- [nio-9999-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2015-11-19 12:04:24.553 DEBUG 41954 --- [nio-9999-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2015-11-19 12:04:24.567 DEBUG 41954 --- [nio-9999-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/authorize'; against '/css/**'
2015-11-19 12:04:24.567 DEBUG 41954 --- [nio-9999-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/authorize'; against '/js/**'
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/authorize'; against '/images/**'
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/authorize'; against '/**/favicon.ico'
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/authorize'; against '/error'
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.security.web.FilterChainProxy : /oauth/authorize at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.security.web.FilterChainProxy : /oauth/authorize at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.security.web.FilterChainProxy : /oauth/authorize at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@335f832b
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.security.web.FilterChainProxy : /oauth/authorize at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://localhost:9999/uaa/oauth/authorize
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2015-11-19 12:04:24.568 DEBUG 41954 --- [nio-9999-exec-4] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

我怀疑它失败是因为 OAuth 服务器上的“http://localhost:9999/uaa/oauth/authorize 发现无效的 CSRF token ”,但在 http 安全性中禁用 csrf 保护后,相同的错误仍然存​​在。不确定为什么 CSRF 在从等式中删除 JWT 后会成为问题。

任何帮助将不胜感激。谢谢。

最佳答案

我遇到了类似的问题,那就是我没有将身份验证服务器的上下文路径设置为 /uaa 。我的建议是从“Spring Security 和 Angular JS”的相同副本开始,然后逐步迈向您的自定义解决方案。每个步骤之后,运行示例并查看一切是否仍然有效。这样您就可以轻松地找出导致问题的原因。

关于Spring Security OAuth2 在没有 JWT 的情况下无法工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33812805/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com