1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Spring Cloud OAuth2 JWT 微服务认证服务器得构建

Spring Cloud OAuth2 JWT 微服务认证服务器得构建

时间:2019-03-26 09:55:50

相关推荐

Spring Cloud OAuth2 JWT 微服务认证服务器得构建

文章目录

Spring Cloud OAuth2 JWT 微服务认证服务器得构建前言认证服务得搭建 `AuthorizationServer``WebSecurityConfig``AuthorizationServerConfig``JwtTokenConfig``JwtTokenEnhancer`数据库表结构资源服务器得搭建`JwtTokenConfig``JwtTokenEnhancer``ResourceConfiguration``OauthCallBackController``application.yml`测试

Spring Cloud OAuth2 JWT 微服务认证服务器得构建

前言

这里说点废话 , 在Spring Cloud 中我们讲模块拆分成各个小的服务,各个服务之间通过远程请求进行调用,这样得架构我们称之为微服务。在单体架构中,用户得认证得和授权都是在一个服务中进行。

然后我们说说微服务中我们是怎么处理微服务的登录,权限,认证。

然后说说Spring Cloud 中得一些概念 这是重点啊 ,重点 ,重点。首先说一下我们是用OAuth2 协议来做用户认证得 ,Spring Cloud 中集成了这个模块

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId></dependency>

这里面集成好了Spring Security 模块,所以不需要我们再次对Secuirty进行集成。

认证服务得搭建AuthorizationServer

这里我们先说下流程 , 就是我们平时使用得用户进入某宝然后进行选择登录,登录选项有很多,比如说支付宝登录 , 那么它呢请求得就是支付宝得OAuth2接口进行得认证,然后呢在某宝自己服务这里根据OAuth2协议的回调结果再进行处理,从而主动对该用户进行认证通过并赋予哪些角色,也就是拥有哪些权限。

同样这样得架构在我们这里也可以进行实现。我们使用得就是Spring Security OAuth2进行实现得。首先有一个授权服务,这里说明下授权,仅仅是授权,也就是负责签发token,不对用户得权限进行限制。授权成功后授权服务器回生成一个code,然后回调进入我们注册好得回调地址,并且将code携带进入,然后这时候我们这个服务(注意这里是别的服务了,属于资源服务了,不是认证服务,认证服务回调进入资源服务), 然后我们资源服务利用这个code,再去请求认证服务,来获取access_token,当我们获取到这个token得时候,我们将token信息加入到response header中,这样前端每次请求中都要携带这个token才可以访问资源。(授权码模式)接下来访问资源得时候,我们还要对用户访问得资源进行校验,看是否符合权限,因此我们还需要个权限服务,用户来获取用户都有哪些权限得服务。

当然这只是一种方案 ,还有其他方案,比如说我们只在网关处校验权限。

WebSecurityConfig

首先说这个类,这个类是属于Spring Security的 ,它使用最上面的过滤链,主要是配置哪些接口可以访问不可以访问,权限就是在这里进行限制的。

@Order(1)@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate DataSource dataSource;@Autowiredprivate UserDetailsService baseUserDetailsService;@Autowiredprivate BlogUserMapper blogUserMapper;@Value("${security.remember.time}")private Integer rememberTime;@Value("${security.oauth2.secret}")private String secret;/*配置TokenRepository*/@Beanpublic PersistentTokenRepository persistentTokenRepository() {JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();jdbcTokenRepository.setDataSource(dataSource);// jdbcTokenRepository.setCreateTableOnStartup(true);return jdbcTokenRepository;}@Beanpublic PasswordEncoder passwordEncoder() {return new Pbkdf2PasswordEncoder(secret);}@Bean@Primary@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** @Author myk* @Description //用户验证* @Date 10:05 /12/24* @Param [auth]* @return void**/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(baseUserDetailsService).passwordEncoder(passwordEncoder());}/*** 允许匿名访问所有接口 主要是 oauth 接口* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and().csrf().disable().authorizeRequests().antMatchers("/security/login","/oauth/**","/actuator/**").permitAll().antMatchers("/js/**","/html/**","/img/**","/font/**","/css/**","/layer/**").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/html/login.html").loginProcessingUrl("/security/login").and().logout().logoutUrl("/security/logout").and().rememberMe().tokenRepository(persistentTokenRepository())//两个星期.tokenValiditySeconds(rememberTime);}

AuthorizationServerConfig

这个类是用来Security 集成OAuth2的,注意这里使用了@EnableAuthorizationServer注解,配置为一个认证中心

这里使用的数据存储的客户端信息,一会来解释数据库中字段的参数是用来做什么的,并且这里配置了jwt增强类,将我们的用户信息写入了jwt中,当然密码不能写进来。

@Configuration@EnableAuthorizationServerpublic class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredpublic UserDetailsService baseUserDetailsService;@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate TokenStore jwtTokenStore;@Autowiredprivate JwtAccessTokenConverter jwtAccessTokenConverter;@Autowiredprivate DataSource dataSource;@Autowiredprivate JwtTokenEnhancer jwtTokenEnhancer;@Bean("jdbcClientDetailsService")public JdbcClientDetailsService getJdbcClientDetailsService() {return new JdbcClientDetailsService(dataSource);}@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {//允许表单验证security.allowFormAuthenticationForClients()//开启 /oauth/token_key 验证端口无权限访问.tokenKeyAccess("permitAll()")// 开启 /oauth/check_token 验证端口认证权限访问.checkTokenAccess("isAuthenticated()");}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {// 使用JdbcClientDetailsService客户端详情服务clients.withClientDetails(getJdbcClientDetailsService());}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {// 普通jwt 模式 支持password 模式endpoints.authenticationManager(authenticationManager).allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST,HttpMethod.OPTIONS)//.userDetailsService(baseUserDetailsService).tokenStore(jwtTokenStore);endpoints.tokenServices(defaultTokenServices());endpoints.allowedTokenEndpointRequestMethods(HttpMethod.POST,HttpMethod.GET,HttpMethod.OPTIONS);}/*** <p>注意,自定义TokenServices的时候,需要设置@Primary,否则报错,</p>* @return*/@Primary@Beanpublic DefaultTokenServices defaultTokenServices(){//添加用户信息List<TokenEnhancer> tokenEnhancerList = new ArrayList<>();tokenEnhancerList.add(jwtTokenEnhancer);tokenEnhancerList.add(jwtAccessTokenConverter);TokenEnhancerChain enhancerChain = new TokenEnhancerChain();enhancerChain.setTokenEnhancers(tokenEnhancerList);DefaultTokenServices tokenServices = new DefaultTokenServices();tokenServices.setTokenStore(jwtTokenStore);tokenServices.setSupportRefreshToken(true);tokenServices.setClientDetailsService(getJdbcClientDetailsService());tokenServices.setAccessTokenValiditySeconds(60*60*12); // token有效期自定义设置,默认12小时tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);//默认30天,这里修改tokenServices.setTokenEnhancer(enhancerChain);return tokenServices;}}

JwtTokenConfig

@Configurationpublic class JwtTokenConfig {@Bean@Primarypublic TokenStore jwtTokenStore(){return new JwtTokenStore(jwtAccessTokenConverter());}/*** @Author myk* @Description 转换器* @Date 16:19 /12/17* @Param []* @return org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter**/@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter() {final JwtAccessTokenConverter converter = new JwtTokenEnhancer();// 导入证书,这里我们使用jdk加密tokenKeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("ailuoli.jks"), "Ws961226".toCharArray());converter.setKeyPair(keyStoreKeyFactory.getKeyPair("ailuoli"));return converter;}}

JwtTokenEnhancer

jwt 增强类

@Componentpublic class JwtTokenEnhancer extends JwtAccessTokenConverter {/*** @Author myk* @Description //将用户信息写入token* @Date 16:24 /12/17* @Param [oAuth2AccessToken, oAuth2Authentication]* @return org.springframework.mon.OAuth2AccessToken**/@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {DefaultOAuth2AccessToken defaultOAuth2AccessToken = new DefaultOAuth2AccessToken(oAuth2AccessToken);BaseSecurityUser blogUser = (BaseSecurityUser) oAuth2Authentication.getPrincipal();blogUser.setCredential(null);defaultOAuth2AccessToken.getAdditionalInformation().put(Constant.USER_INFO,blogUser);return super.enhance(defaultOAuth2AccessToken,oAuth2Authentication);}/*** 解析token* @param value* @param map* @return*/@Overridepublic OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map){OAuth2AccessToken oauth2AccessToken = super.extractAccessToken(value, map);convertData(oauth2AccessToken, oauth2AccessToken.getAdditionalInformation());return oauth2AccessToken;}private void convertData(OAuth2AccessToken accessToken, Map<String, ?> map) {accessToken.getAdditionalInformation().put(Constant.USER_INFO,convertUserData(map.get(Constant.USER_INFO)));}private BlogUser convertUserData(Object map) {String json = JsonUtils.deserializer(map);return JsonUtils.serializable(json, BlogUser.class);}}

数据库表结构

-- ------------------------------ Table structure for ClientDetails-- ----------------------------DROP TABLE IF EXISTS `ClientDetails`;CREATE TABLE `ClientDetails` (`appId` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`resourceIds` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`appSecret` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`scope` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`grantTypes` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`redirectUrl` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`authorities` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`access_token_validity` int(11) NULL DEFAULT NULL,`refresh_token_validity` int(11) NULL DEFAULT NULL,`additionalInformation` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`autoApproveScopes` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,PRIMARY KEY (`appId`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Table structure for oauth_access_token-- ----------------------------DROP TABLE IF EXISTS `oauth_access_token`;CREATE TABLE `oauth_access_token` (`token_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`token` blob NULL,`authentication_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`user_name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`client_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`authentication` blob NULL,`refresh_token` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,PRIMARY KEY (`authentication_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Table structure for oauth_approvals-- ----------------------------DROP TABLE IF EXISTS `oauth_approvals`;CREATE TABLE `oauth_approvals` (`userId` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`clientId` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`scope` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`expiresAt` timestamp(0) NULL DEFAULT NULL,`lastModifiedAt` timestamp(0) NULL DEFAULT NULL) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Table structure for oauth_client_details-- ----------------------------DROP TABLE IF EXISTS `oauth_client_details`;CREATE TABLE `oauth_client_details` (`client_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`resource_ids` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`client_secret` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`scope` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`authorized_grant_types` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`web_server_redirect_uri` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`authorities` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`access_token_validity` int(11) NULL DEFAULT NULL,`refresh_token_validity` int(11) NULL DEFAULT NULL,`additional_information` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`autoapprove` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,PRIMARY KEY (`client_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Table structure for oauth_client_token-- ----------------------------DROP TABLE IF EXISTS `oauth_client_token`;CREATE TABLE `oauth_client_token` (`token_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`token` blob NULL,`authentication_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`user_name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`client_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,PRIMARY KEY (`authentication_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Table structure for oauth_code-- ----------------------------DROP TABLE IF EXISTS `oauth_code`;CREATE TABLE `oauth_code` (`code` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`authentication` blob NULL) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Table structure for oauth_refresh_token-- ----------------------------DROP TABLE IF EXISTS `oauth_refresh_token`;CREATE TABLE `oauth_refresh_token` (`token_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`token` blob NULL,`authentication` blob NULL) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

这里其中最关键的表就是oauth_client_details

client_id首先说的就是这个,因为刚才搭建的是server,所以再它看来,其他要它进行认证的服务都是client,这个是client的标识,不能重复,相当于用户的用户名resource_ids是客户端拥有访问资源的id集合client_secret这是相当于用户的密码,只不过它是用来认证客户端的,需要加密scope这个字段是授权访问的作用域 all, select,read,write 等authorized_grant_types这个是Oauth2 认证的类型,我们本文描述的是授权码类型,参数有authorization_code,refresh_tokenweb_server_redirect_uri这个是回调到客户端的地址比如http://127.0.0.1:9001/user/service/oauth/callbackaccess_token_validityaccess_token 的有效期refresh_token_validityrefresh_token_validity的有效期autoapprove是否需要用户手动授权,false 就需要手动点击授权

如果会一些spring security的知识 这里我们应该可以看得懂 , 授权服务器搭建就到这里

数据截图

资源服务器得搭建

JwtTokenConfig

同样是jwt配置类 ,这里是对jwt进行得解析,需要jdk加密得公钥

@Configurationpublic class JwtTokenConfig {@Bean@Primarypublic TokenStore jwtTokenStore(){return new JwtTokenStore(jwtAccessTokenConverter());}/*** @Author myk* @Description 转换器* @Date 16:19 /12/17* @Param []* @return org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter**/@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter() {//用作 JWT 转换器JwtAccessTokenConverter converter = new JwtAccessTokenConverter();Resource resource = new ClassPathResource("public.cert");String publicKey ;try {publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));} catch (IOException e) {throw new RuntimeException(e);}converter.setVerifierKey(publicKey); //设置公钥return converter;}}

JwtTokenEnhancer

这个类和认证服务器得一样

ResourceConfiguration

这个类标记了@EnableResourceServer注解 表明它是个资源服务器们也就是一个客户端(client)

@Configuration@EnableResourceServerpublic class ResourceConfiguration extends ResourceServerConfigurerAdapter {@Autowiredprivate TokenStore jwtTokenStore;@Value("${security.oauth2.secret}")private String secret;@Beanpublic PasswordEncoder passwordEncoder() {return new Pbkdf2PasswordEncoder(secret);}@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {resources.tokenStore(jwtTokenStore);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.cors().and().csrf().disable().authorizeRequests().antMatchers("/blog/user_info","/oauth/**","/actuator/**","/sys/user/register").permitAll().anyRequest().authenticated();}}

OauthCallBackController

重点来了 ,这个回调地址,我们在数据库中配置得地址,会携带code进入这个类,然后这个类中再去使用rest请求token。注意类型是MediaType.MULTIPART_FORM_DATA,不是json

package com.cloud.blog.user.controller;import com.mon.config.exception.BlogResponse;import com.cloud.blog.user.config.pojo.JWT;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.http.HttpEntity;import org.springframework.http.HttpHeaders;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.util.LinkedMultiValueMap;import org.springframework.util.MultiValueMap;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;import javax.servlet.http.HttpServletRequest;/*** @ClassName BlogCallBackController* @Description 接受认证成功的回调地址* @Author wsail* @Date /12/27 15:16**/@RestControllerpublic class OauthCallBackController {@Value("${security.oauth2.client.access-token-uri}")private String oauth_token;@Value("${security.oauth2.client.registered-redirect-uri}")private String redirect_uri;@Value("${security.oauth2.client.authorized-grant-types}")private String grant_type;@Value("${security.oauth2.client.client-id}")private String client_id;@Value("${security.oauth2.client.client-secret}")private String client_secret;private final static String CONTENT_TYPE = "Content-Type";@Autowiredprivate RestTemplate restTemplate;@GetMapping(value = "/oauth/callback",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)public BlogResponse<JWT> authorizationSuccessCallBack(String code, HttpServletRequest request){System.out.println(request.getMethod());HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);MultiValueMap<String,String> map = new LinkedMultiValueMap<>();map.add("client_id",client_id);map.add("client_secret",client_secret);map.add("code",code);map.add("redirect_uri",redirect_uri);map.add("grant_type",grant_type);httpHeaders.add(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);HttpEntity<MultiValueMap<String,String>> httpEntity = new HttpEntity<>(map,httpHeaders);ResponseEntity<JWT> responseEntity = restTemplate.postForEntity(oauth_token,httpEntity,JWT.class);JWT jwt = responseEntity.getBody();return new BlogResponse<>(jwt);}}

application.yml

资源服务得配置,有坑! 有坑 !有坑!

注意这里得resource token-info-uri一定要写 ,一定要写 ,一定要写对 ,不让使用token请求数据得时候会抛出异常

security:oauth2:client:client-id: user-serviceclient-secret: Ws961226user-authorization-uri: http://127.0.0.1:9527/auth/server/oauth/authorizeaccess-token-uri: http://127.0.0.1:9527/auth/server/oauth/tokenregistered-redirect-uri: http://127.0.0.1:9001/user/service/oauth/callbackauthorized-grant-types: authorization_coderesource:token-info-uri: http://127.0.0.1:9527/auth/server/oauth/check_token # 检查 token 是否有效authorization:check-token-access: http://127.0.0.1:9527/auth/server/oauth/check_token

测试

到这里我们得资源服务器也搭建完成 ,上成果

访问进行登录127.0.0.1:9527/auth/server/oauth/authorize?response_type=code&client_id=user-service&redirect_uri=http://127.0.0.1:9001/user/service/oauth/callback

成功被认证服务security进行拦截,并跳转到了登录界面 ,我们登录

成功将jwt信息进行了返回,然后我们先请求一个资源服务得接口,不添加token得情况

显然是被Oauth 进行了拦截,然后我们添加token试试

成功!至此OAuth2集成就完成了 ,接下来就是对用户权限得进行限制,我们还需要搭建权限服务,这里就不赘述了,有兴趣得小伙伴可以自己试试。2665151959@ 有问题可以问我

git源码在下面git源码

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。