当前位置: 首页 > news >正文

人才招聘网站开发 源代码宁波微信推广平台哪个好

人才招聘网站开发 源代码,宁波微信推广平台哪个好,苏州网站建设找哪家,舟山网站开发SpringSecurity简介 spring Security是什么? Spring Security 是一个强大且高度可定制的身份验证和访问控制框架,用于保护基于Spring的应用程序。它是Spring项目的一部分,旨在为企业级系统提供全面的安全性解决方案。 一个简单的授权和校验…

 SpringSecurity简介

spring Security是什么?

Spring Security 是一个强大且高度可定制的身份验证和访问控制框架,用于保护基于Spring的应用程序。它是Spring项目的一部分,旨在为企业级系统提供全面的安全性解决方案。

一个简单的授权和校验流程

检验流程

总流程 

SpringSecurity使用

认证 

对应依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>

在自定义检验的时候,主要就是实现UserDetailsService接口,重写loadUserByUserName方法,在该方法中就是去检验账号和密码的准确性。(一般都是进行数据库的查询校验,默认的密码格式就是 ·{}密码·)

前后端分离项目登录流程

1.在springSecurity中我们的需要设置密文的配置,在项目中大多都是使 BCryptPasswordEncoder类来做密码的加密。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}

2.创建对应的login接口和service

Controller 

@RestController
@RequestMapping("/user")
public class LoginController {@AutowiredLoginService loginService;@PostMapping("/login")public ResponseResult login(@RequestBody User user) {return loginService.login(user);}
}

Service

@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate AuthenticationManager authenticationManager;@AutowiredRedisCache redisCache;@Overridepublic ResponseResult login(User user) {//authenticationManager authenticate进行用户验证UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());Authentication authenticate = authenticationManager.authenticate(authenticationToken);//执行我们对饮的认证方法,在该方法中会返回LoginUser类型的数据//如果没有通过通过直接抛异常if(ObjectUtil.isEmpty(authenticate)) {throw new RuntimeException("登录失败");}//如果成功直接生成token,将其也map返回LoginUser loginUser = (LoginUser)authenticate.getPrincipal();String jwt = JwtUtil.createJWT(loginUser.getUser().getId().toString());Map<String, String> data = new HashMap<>();data.put("token", jwt);redisCache.setCacheObject(loginUser.getUser().getId().toString(), user);//返回tokenreturn new ResponseResult(200, "登录成功", data);}
}

因为AuthenticationManager默认不在ioc中,我们需要将其配置到ioc中,并且配置对应的校验规则。在里面就包括 无效校验的接口(比如:登录接口)和其他一些前后端分离的配置。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//将AuthenticationManager配置到ioc中@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http//由于是前后端分离项目,所以要关闭csrf.csrf().disable()//由于是前后端分离项目,所以session是失效的,我们就不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//指定让spring security放行登录接口的规则.authorizeRequests()// 对于登录接口 anonymous表示允许匿名访问.antMatchers("/user/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();}
}

进行测试,校验成功。

前后端分离项目校验流程

1.创建一个校验过滤器

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@AutowiredRedisCache redisCache;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//获取token,token会存在header中String token = request.getHeader("token");if(StrUtil.isEmpty(token)) {//由后续的拦截器进行拦截filterChain.doFilter(request, response);//后续会返回回来,需要return,不然会执行下面的语句return ;}//解析tokenString userId;try {Claims claims = JwtUtil.parseJWT(token);userId = claims.getSubject();if(StringUtil.isNullOrEmpty(userId)) {throw new RuntimeException("token解析失败");}} catch (Exception e) {throw new RuntimeException(e);}//从redis中获取用户的信息LoginUser loginUser = redisCache.getCacheObject(userId);if(ObjectUtil.isEmpty(loginUser)) {throw new RuntimeException("Redis中没有用户信息");}//将数据存储到SecurityContextHolderUsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);//放行filterChain.doFilter(request, response);}
}

使用三个参数的UsernamePasswordAuthenticationToken的构造器,该构造器会设置授权成功。

2.将过滤器设置到用户验证过滤器之前

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredJwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;//设置加密方式@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//将AuthenticationManager配置到ioc中@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http//由于是前后端分离项目,所以要关闭csrf.csrf().disable()//由于是前后端分离项目,所以session是失效的,我们就不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//指定让spring security放行登录接口的规则.authorizeRequests()// 对于登录接口 anonymous表示允许匿名访问.antMatchers("/user/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();//将过滤器添加到用户登录处理器之前http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}
}

进行测试,将成功的token放入header中,进行校验。最终校验成功。

退出登录流程

1.编写退出登录接口

@RestController
@RequestMapping("/user")
public class LoginController {@AutowiredLoginService loginService;@RequestMapping("/logout")public ResponseResult logout() {return loginService.logout();}
}

2.编写service实现类,删除redis中用户信息的数据,即可完成退出登录操作。在解析的时候redis中的数据不存在就会直接被拦截。

@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate AuthenticationManager authenticationManager;@AutowiredRedisCache redisCache;@Overridepublic ResponseResult logout() {//在进入此接口时会先进行解析,成功之后才会执行logout,此时SecurityContextHolder中是有用户信息的UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();LoginUser loginUser = (LoginUser) authentication.getPrincipal();if(ObjectUtil.isEmpty(loginUser)) {throw new RuntimeException("LoginUser不存在");}//把redis中的数据删除之后,下次解析的时候就会直接报错,在解析中我们对redis的数据做了判空的操作redisCache.deleteObject(loginUser.getUser().getId().toString());return new ResponseResult(200, "退出登录成功", null);}
}

进行测试,最终成功。

授权

1.开启授权功能,在对应的security的配置类中添加对应的注解。

@EnableGlobalMethodSecurity(prePostEnabled = true) //开启授权

2.为接口设置对应的权限需求

@RestController
public class baseController {@RequestMapping("/hello")//拥有text倾向才能访问@PreAuthorize("hasAuthority('text')")public String hello() {return "hello!";}
}

3.在用户进行认证的时候查询用户拥有的权限集合,并设置到 authenticationToken中。

  • 在返回类型中设置权限集合属性和重写获取权限集合方法。
@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {private User user;private List<String> authorities2String;public LoginUser(User user, List<String> authorities2String) {this.user = user;this.authorities2String = authorities2String;}@JSONField(serialize = false)private List<GrantedAuthority> authorities;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {if(CollUtil.isEmpty(authorities)) {return authorities2String.stream().map(item -> new SimpleGrantedAuthority(item)).collect(Collectors.toList());}return authorities;}@Overridepublic String getPassword() {return user.getPassword();}@Overridepublic String getUsername() {return user.getUserName();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}
  • 在校验Service中查询对应的权限列表。
@Service
public class UserService implements UserDetailsService {@AutowiredUserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {QueryWrapper<com.huang.springsecuritydemo.entity.User> userQueryWrapper = new QueryWrapper<>();userQueryWrapper.eq("user_name", username);com.huang.springsecuritydemo.entity.User user = userMapper.selectOne(userQueryWrapper);if(ObjectUtil.isEmpty(user)) {throw new RuntimeException("用户不存在");}//todo 查询并设置对应的权限信息//模拟查到的权限信息List<String> data = Arrays.asList("test", "text");return new LoginUser(user, data);}
}
  • 在JWT认证中向authenticationToken中设置权限集合,最终设置到SecurityContextHolder中。
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@AutowiredRedisCache redisCache;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//获取token,token会存在header中String token = request.getHeader("token");if(StrUtil.isEmpty(token)) {//由后续的拦截器进行拦截filterChain.doFilter(request, response);//后续会返回回来,需要return,不然会执行下面的语句return ;}//解析tokenString userId;try {Claims claims = JwtUtil.parseJWT(token);userId = claims.getSubject();if(StringUtil.isNullOrEmpty(userId)) {throw new RuntimeException("token解析失败");}} catch (Exception e) {throw new RuntimeException(e);}//从redis中获取用户的信息LoginUser loginUser = redisCache.getCacheObject(userId);if(ObjectUtil.isEmpty(loginUser)) {throw new RuntimeException("Redis中没有用户信息");}//将数据存储到SecurityContextHolder//todo 设置对应的权限信息UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);//放行filterChain.doFilter(request, response);}
}

进行测试,授权成功。

RDAB模型例子(基本通用,看进行二次开发)

1.创建五个数据库 用户表,角色表,权限表,用户角色关联表,角色权限关联表。

2.编写SQL语句查询用户的所有权限,并使用 mybatis-plus进行封装为一个函数进行调用。

SELECTDISTINCT m.`perms`FROMsys_user_role urLEFT JOIN `sys_role` r ON ur.`role_id` = r.`id`LEFT JOIN `sys_role_menu` rm ON ur.`role_id` = rm.`role_id`LEFT JOIN `sys_menu` m ON m.`id` = rm.`menu_id`WHEREuser_id = #{id}AND r.`status` = 0AND m.`status` = 0

3.在校验是进行调用,并返回对应的权限集合。

@Service
public class UserService implements UserDetailsService {@AutowiredUserMapper userMapper;@AutowiredMenuMapper menuMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {QueryWrapper<com.huang.springsecuritydemo.entity.User> userQueryWrapper = new QueryWrapper<>();userQueryWrapper.eq("user_name", username);com.huang.springsecuritydemo.entity.User user = userMapper.selectOne(userQueryWrapper);if(ObjectUtil.isEmpty(user)) {throw new RuntimeException("用户不存在");}//todo 查询并设置对应的权限信息List<String> data = menuMapper.selectPermsByUserId(user.getId());return new LoginUser(user, data);}
}

修改接口所需要的权限。

@RestController
public class baseController {@RequestMapping("/hello")//拥有text倾向才能访问@PreAuthorize("hasAuthority('system:test:list')")public String hello() {return "hello!";}
}

进行测试,最终成功。

自定义失败处理

1.自定义授权异常处理器和校验异常处理器。

  • 校验异常处理器
//校验失败异常处理器
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {//创建统一的返回对象,设置到response中ResponseResult responseResult = new ResponseResult(HttpStatus.HTTP_UNAUTHORIZED, "校验失败!");String json = JSON.toJSONString(responseResult);//将统一的结果设置到Response中,本质就是将对应的数据设置到response中WebUtil.renderString(response, json);}
}
  • 授权异常处理器

//授权失败异常处理器
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {ResponseResult responseResult = new ResponseResult(HttpStatus.HTTP_UNAUTHORIZED, "授权失败!");String json = JSON.toJSONString(responseResult);WebUtil.renderString(response, json);}
}

对应的webUtil工具类

public class WebUtil {/*** 将字符串渲染到客户端** @param response 渲染对象* @param string 待渲染的字符串* @return null*/public static String renderString(HttpServletResponse response, String string) {try{response.setStatus(200);response.setContentType("application/json");response.setCharacterEncoding("utf-8");//将结果json以流的形式写入response中response.getWriter().print(string);}catch (IOException e){e.printStackTrace();}return null;}
}

2.将自定义的异常处理器进行配置

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredJwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@AutowiredAuthenticationEntryPoint authenticationEntryPoint;@AutowiredAccessDeniedHandler accessDeniedHandler;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//将AuthenticationManager配置到ioc中@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http//由于是前后端分离项目,所以要关闭csrf.csrf().disable()//由于是前后端分离项目,没有session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//指定让spring security放行登录接口的规则.authorizeRequests()// 对于登录接口 anonymous表示允许匿名访问, permitAll就是 登录和没登录都可以访问.antMatchers("/user/login").anonymous() //匿名访问,未登录就可以访问// 除上面外的所有请求全部需要鉴权认证后访问.anyRequest().authenticated();//将过滤器添加到用户登录处理器之前http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//设置自定义的异常处理器http.exceptionHandling()//校验异常处理器.authenticationEntryPoint(authenticationEntryPoint)//授权异常处理器.accessDeniedHandler(accessDeniedHandler);}
}

进行测试,异常显示成功。

允许跨域

1.开启springboot的允许跨域。

@Configuration
public class CorsConfig implements WebMvcConfigurer {@Override//重写spring提供的WebMvcConfigurer接口的addCorsMappings方法public void addCorsMappings(CorsRegistry registry) {//设置可以跨域的映射地址registry.addMapping("/**")// 设置可以跨域的源.allowedOriginPatterns("*")// 是否允许使用cookie.allowCredentials(true)// 设置允许的请求方式.allowedMethods("GET", "POST", "DELETE", "PUT")// 设置允许的header属性.allowedHeaders("*")// 跨域允许时间.maxAge(3600);}
}

2.开启springsecurity的允许跨域。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredJwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@AutowiredAuthenticationEntryPoint authenticationEntryPoint;@AutowiredAccessDeniedHandler accessDeniedHandler;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//将AuthenticationManager配置到ioc中@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {http//由于是前后端分离项目,所以要关闭csrf.csrf().disable()//由于是前后端分离项目,没有session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//指定让spring security放行登录接口的规则.authorizeRequests()// 对于登录接口 anonymous表示允许匿名访问, permitAll就是 登录和没登录都可以访问.antMatchers("/user/login").anonymous() //匿名访问,未登录就可以访问// 除上面外的所有请求全部需要鉴权认证后访问.anyRequest().authenticated();//将过滤器添加到用户登录处理器之前http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//设置自定义的异常处理器http.exceptionHandling()//校验异常处理器.authenticationEntryPoint(authenticationEntryPoint)//授权异常处理器.accessDeniedHandler(accessDeniedHandler);//允许跨域http.cors();}
}

最终设置完成。

自定义权限校验方法(比较灵活,可以自定义策略)

1.自定义校验类

@Component("itolen") //设置该类在ioc中的名称
public class ExpressionRoot {//判断权限是否存在public boolean hasAuthority(String authority) {LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();List<String> authorities2String = loginUser.getAuthorities2String();return authorities2String.contains(authority);}
}

2.在对应的接口上调用自定义方法。

@RestController
public class baseController {@RequestMapping("/hello")//拥有text倾向才能访问@PreAuthorize("@itolen.hasAuthority('system:test:list')")public String hello() {return "hello!";}
}

进行测试。

 其他处理器 

  • 认证成功处理器和认证失败处理器
//认证成功处理器实现类
@Component
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {//认证成功后就会进行该方法System.out.println("认证成功!");}
}
//认证失败处理器实现类
@Component
public class AuthenticationFailureHandlerImpl implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {//认证失败后执行该方法System.out.println("认证失败!");}
}

 将两个类进行配置。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate AuthenticationSuccessHandler authenticationSuccessHandler;@Autowiredprivate AuthenticationFailureHandler authenticationFailureHandler;//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {//设置校验成功处理器和校验失败处理器http.formLogin().successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler);}
}
  • 注销成功处理器
@Component
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {//注销成功后执行的方法System.out.println("注销成功!");}
}

将该类进行配置。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate LogoutSuccessHandler logoutSuccessHandler;//配置权限规则,主要就睡要放行登录接口,不然登录接口都会被了解,以及其他不要的前后端分离的配置@Overrideprotected void configure(HttpSecurity http) throws Exception {//设置注销成功处理器http.logout().logoutSuccessHandler(logoutSuccessHandler);}
}


文章转载自:
http://premedical.tzmc.cn
http://gazar.tzmc.cn
http://sonifier.tzmc.cn
http://conferree.tzmc.cn
http://cornemuse.tzmc.cn
http://whitefly.tzmc.cn
http://negro.tzmc.cn
http://roorbach.tzmc.cn
http://offenceful.tzmc.cn
http://daffodil.tzmc.cn
http://ceruloplasmin.tzmc.cn
http://steadiness.tzmc.cn
http://jalor.tzmc.cn
http://chevrolet.tzmc.cn
http://zymoplastic.tzmc.cn
http://cousinry.tzmc.cn
http://platitudinarian.tzmc.cn
http://molluscan.tzmc.cn
http://acidic.tzmc.cn
http://scintiscanning.tzmc.cn
http://obturator.tzmc.cn
http://sinology.tzmc.cn
http://plessor.tzmc.cn
http://corncrib.tzmc.cn
http://trireme.tzmc.cn
http://sermonesque.tzmc.cn
http://athwartships.tzmc.cn
http://bacteremic.tzmc.cn
http://byzantinesque.tzmc.cn
http://spunbonded.tzmc.cn
http://teilhardian.tzmc.cn
http://midwifery.tzmc.cn
http://concanavalin.tzmc.cn
http://carbamic.tzmc.cn
http://slam.tzmc.cn
http://fractocumulus.tzmc.cn
http://hematopoiesis.tzmc.cn
http://recapitalization.tzmc.cn
http://lisp.tzmc.cn
http://frontcourt.tzmc.cn
http://ceramic.tzmc.cn
http://puddler.tzmc.cn
http://romany.tzmc.cn
http://paiute.tzmc.cn
http://coypu.tzmc.cn
http://hetmanate.tzmc.cn
http://gyp.tzmc.cn
http://looped.tzmc.cn
http://chute.tzmc.cn
http://osculum.tzmc.cn
http://cuesta.tzmc.cn
http://sopaipilla.tzmc.cn
http://euphemious.tzmc.cn
http://coeditor.tzmc.cn
http://milksop.tzmc.cn
http://subcranial.tzmc.cn
http://wormy.tzmc.cn
http://foursquare.tzmc.cn
http://sublineate.tzmc.cn
http://taxloss.tzmc.cn
http://patency.tzmc.cn
http://bruit.tzmc.cn
http://sowbug.tzmc.cn
http://acetophenetidin.tzmc.cn
http://epistoler.tzmc.cn
http://dusty.tzmc.cn
http://homozygosity.tzmc.cn
http://turfan.tzmc.cn
http://popularise.tzmc.cn
http://arachis.tzmc.cn
http://interfluent.tzmc.cn
http://soutar.tzmc.cn
http://frustule.tzmc.cn
http://popish.tzmc.cn
http://uranous.tzmc.cn
http://countersubject.tzmc.cn
http://ergot.tzmc.cn
http://retrochoir.tzmc.cn
http://rote.tzmc.cn
http://subequal.tzmc.cn
http://hegelian.tzmc.cn
http://vainly.tzmc.cn
http://grandson.tzmc.cn
http://pinwale.tzmc.cn
http://seismoscopic.tzmc.cn
http://polypary.tzmc.cn
http://chinquapin.tzmc.cn
http://biobibliography.tzmc.cn
http://tunesmith.tzmc.cn
http://drizzly.tzmc.cn
http://wrathful.tzmc.cn
http://chorizo.tzmc.cn
http://karl.tzmc.cn
http://anywise.tzmc.cn
http://cried.tzmc.cn
http://lebensspur.tzmc.cn
http://commonsensible.tzmc.cn
http://ventage.tzmc.cn
http://immortality.tzmc.cn
http://compendiously.tzmc.cn
http://www.dt0577.cn/news/61484.html

相关文章:

  • 19网站建设网站黄页推广软件
  • 如何做漂亮的网站首页湘潭网站设计
  • 网站开发中都引用什么文献产品线上推广方案
  • 分析网站建设流程关键词列表
  • 怎么做网站讯息推广软文范文800字
  • 企业备案网站服务内容百度一下 你就知道官方
  • 自己有网站怎么赚钱seo的优化方向
  • 一个网站开发环境是什么企业文化是什么
  • 网购网站建设企业网站建站模板
  • 公司做网站买域名之后做什么家庭优化大师免费下载
  • 建筑设计资料网站广告营销的经典案例
  • 做社情网站犯法怎么办百度商城购物
  • wordpress重装之后夫唯seo
  • 个人网站是请人做还是自己编写好博客seo教程
  • 做网站后端需要什么语言北京网络营销推广外包
  • wordpress七牛seo实战密码电子书
  • 网站百度流量怎么做app推广地推接单网
  • 科技服务网站建设方案什么推广平台好
  • 哪里有免费服务器关键词排名优化公司
  • 做旅行的网站推广宣传
  • 哪些网站可以做招生嘉兴关键词优化报价
  • 株洲seo优化加盟新网站seo外包
  • 佛山知名营销网站开发灰色词快速排名接单
  • 专业ppt代做网站关键词优化排名公司
  • 网站建设费算费用还是固定资产成年培训班有哪些
  • 服务周到的微网站建设买域名
  • 武汉云优化网站建设互联网营销的特点
  • 典型的网站案例新媒体营销推广公司
  • 网站字体规范青岛网络推广公司
  • 佛山做网站3000跨国网站浏览器