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

运营服务商官方网站企业公司网站源码

运营服务商官方网站,企业公司网站源码,含山县住房和城乡建设局网站,全flash网站下载目录 前言 正文 1.基本流程 2.基本用法 3.配置项 4.HttpSecurity 方式和内存认证方式 5.认证流程 6.基于数据库查询的登录验证 7.多种角色权限认证 8.自定义权限认证 总结 前言 安全对于任何系统来说都是非常重要的#xff0c;权限的分配和管理一直都是开发者需… 目录 前言 正文 1.基本流程 2.基本用法 3.配置项  4.HttpSecurity 方式和内存认证方式  5.认证流程 6.基于数据库查询的登录验证 7.多种角色权限认证  8.自定义权限认证  总结 前言 安全对于任何系统来说都是非常重要的权限的分配和管理一直都是开发者需要特别重视的。一旦缺乏基本和有力的授权验证一些别有用心之人就会利用这个漏洞对开发者的 Web 应用或者其他软件进行不法侵害。Spring Boot 技术中有许多优秀的安全框架和认证授权方案本次将介绍比较流行的框架技术 Spring Security 及其实践应用。 正文 Spring Security 是 Spring Boot 中一款功能强大基于 Spring 的企业级应用的提供安全访问权限的安装框架在实际工程项目中也会经常用到。通过依赖注入的方式可以使用 Spring Security 库提供声明式的安全访问控制功能。它和 Spring Boot 以及其他 Spring 模块紧密相连。 1.基本流程 Spring Security 的原理其实就是一个过滤器链内部包含了提供各种功能的过滤器。  图中只展示了核心过滤器其它的非核心过滤器并没有在图中展示 UsernamePasswordAuthenticationFilter:负责处理我们在登页面填写了用户名密码后的登陆请求。入门案例的认证工作主要有它负责。ExceptionTranslationFilter: 外理过滤器中抛出的任 AccessDeniedException 和 AuthenticationException。FilterSecuritylnterceptor: 负责权限校验的过滤器  通过 debug 查看当前的过滤器链。 package org.example;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext;SpringBootApplication public class Main {public static void main(String[] args) {ConfigurableApplicationContext run SpringApplication.run(Main.class, args);System.out.println(run);//在此处打上断点} } 打开表达式计算面板  run.getBean(DefaultSecurityFilterChain.class) 计算求值 2.基本用法 安装在 pom.xml 中导入依赖即可 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependency 在项目中编写一个测试的接口 /testHi,代码如下 package org.example.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;RestController public class HiController {GetMapping(/hi)public String hi(){return Hi;} }编写一个类更好的配置管理。 package org.example.config;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;/*** Security 配置类*/ EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 认证* param auth* throws Exception*/Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser(freejava).password(new BCryptPasswordEncoder().encode(123456)).roles(VIP1);}/*** 授权* param http* throws Exception*/Overrideprotected void configure(HttpSecurity http) throws Exception {//设置匹配的资源白名单访问http.authorizeRequests().antMatchers(/,/asserts/**,/pages/login.html,/userlogin).permitAll().antMatchers(/level1/**).hasRole(VIP1).antMatchers(/level2/**).hasRole(VIP2).antMatchers(/level3/**).hasRole(VIP3).anyRequest().authenticated();//剩余任何资源必须认证//开启登录页http.formLogin();//开启自动注销http.logout().logoutSuccessUrl(/login);//注销之后来到登录页http.csrf().disable();} }最后运行会出现如下界面 3.配置项  如果想要修改默认的账号和密码可以在 application.properties 文件中加入下面的配置项。 spring.security.user.namefreejava spring.security.user.password123456 spring.security.user.roles[]admin 4.HttpSecurity 方式和内存认证方式  所谓内存认证就是自定义配置类该配置类继承 WebSecurityConfigurerAdapter需要实现一些自定义配置和方法具体代码如下 package org.example.config;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;EnableWebSecurity public class RealSecurityConfig extends WebSecurityConfigurerAdapter {BeanPasswordEncoder passwordEncoder(){//NoOpPasswordEncoder 在高版本的Spring Boot 中已被弃用不建议使用return new BCryptPasswordEncoder();}Autowired PasswordEncoder passwordEncoder;Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().passwordEncoder(passwordEncoder)//使用对应的加密.withUser(admin).password(passwordEncoder.encode(123456))//使用对应的解密.roles(ADMIN,USER).and().withUser(freephp).password(passwordEncoder.encode(123456)).roles(USER);} }上面这段代码中inMemoryAuthentication 代表把这个配置保存在内存中然后使用 withUser 方法增加授权账号用 password 方法设置密码用 roles 来设置账号所属的权限群组。 而 HttpSecurity 是另外一种认证方式也是使用 configure 方法具体代码如下 Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers(/admin/**).hasRole(ADMIN).antMatchers(/user/**).access(hasAnyRole(ADMIN,USER)).anyRequest().authenticated()//任意登录的用户都可以访问.and().formLogin().loginProcessingUrl(/login).permitAll().and().csrf().disable();} 使用 andMatcher 设置需要被授权的 URL 路径access 方法给予某些角色访问权限代码如下。 package org.example.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;RestController public class SwagController {GetMapping(/user/sayHi)public String myUser(){return Hi,user;}GetMapping(/admin/hello)public String admin(){return admin page;}GetMapping(/hello)public String hello(){return hello,man;} }运行项目后访问 http://localhost:8080/admin/hello, 则会要求输入账号和密码使用 admin 账号密码输入 123456即可进入后台 /admin/hello 页面如图。 5.认证流程 Authentication接口: 它的实现类表示当前访问系统的用户封装了用户相关信息。AuthenticationManager接口: 定义了认证Authentication的方法。UserDetailsService接口: 加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。UserDetails接口: 提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回然后将这些信息封装到Authentication对象中。 所以接下来如果要使用数据库做登录验证只要把实现类 InMemoryUserDetailsManager 做一个替换DaoAuthenticationProvider 调用自定义的实现类。让其不再使用内存做认证进入数据库查询实现 UserDetailsService 接口即可。 6.基于数据库查询的登录验证 之前都是使用内存来存储认证数据其实可以考虑使用数据库进行持久化数据存储。这样更加方便进行账号管理也更符合实际项目开发的需求。  创建一个 roles 库然后创建用户表、角色权限表、用户和角色权限关系表。 create database r_security; use r_security; -- 用户表 CREATE TABLE r_users(id int(11) unsigned NOT NULL AUTO_INCREMENT primary key COMMENT 主键,username varchar(50) not null comment 账号名,password varchar(300) not null comment 密码,status tinyint(11) not null comment 账号状态1正常、2被封,created int (11) not null comment 创建时间时间戳); -- 角色权限表 create table r_roles(id int(11) unsigned not null auto_increment comment 主键,name varchar(50) not null comment 角色名,permission_path varchar(500) not null comment 权限路径如/admin/*,primary key (id) ); -- 用户角色权限关系表 create table r_user_roles(id int(11) unsigned not null auto_increment comment 主键,user_id int(11) unsigned not null comment 用户ID,role_id int(11) unsigned not null comment 角色ID,primary key (id),key user_id (user_id),key role_id (role_id),constraint role_id foreign key (role_id) references r_roles(id) ondelete restrict ,constraint user_id foreign key (user_id) references r_users(id) ondelete restrict )为了方便测试先插入几条测试数据r_users 的数据如图 R_roles的数据如图插入三条数据有三种角色一是管理员角色二是 root 权限也就是超级管理员。三是 dba数据管理员。这三种角色可以访问不同的 URL。  用户角色表中插入数据 为了生成上面 r_users 表中加密后的密码攥写了使用 Bcrypt 加密的程序代码如下  import java.util.ArrayList; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; public class BcryptTest {public static void main(String[] args) {ArrayListString passwordArr new ArrayList();passwordArr.add(123456);getUsersEncodePasswords(passwordArr);}private static void getUsersEncodePasswords(ArrayListString passwordArr) {for (String pass :passwordArr){//密码加密BCryptPasswordEncoder passwordEncoder new BCryptPasswordEncoder();String newPassword passwordEncoder.encode(pass);System.out.println( 原始密码是pass,加密密码为newPassword);//对比这两个密码是不是同一个密码boolean match passwordEncoder.matches(pass,newPassword);System.out.println(两个密码一致match);}} } 运行结果如图 Bcrpt 加密算法非常安全此算法自身实现了随机盐生成很难被逆向破解。  创建一个新的项目导入依赖pom.xml代码如下 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdorg.example/groupIdartifactIdSecurity2/artifactIdversion1.0-SNAPSHOT/versionpropertiesmaven.compiler.source8/maven.compiler.sourcemaven.compiler.target8/maven.compiler.targetproject.build.sourceEncodingUTF-8/project.build.sourceEncoding/propertiesparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.3.5.RELEASE/versionrelativePath/ !-- lookup parent from repository --/parentdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency!-- 引入security依赖 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactIdversion2.3.5.RELEASE/version/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion1.1.1/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion1.1.10/version/dependency!-- mysql --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scopeexclusionsexclusiongroupIdorg.junit.vintage/groupIdartifactIdjunit-vintage-engine/artifactId/exclusion/exclusions/dependencydependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.13.2/versionscopetest/scope/dependency/dependencies/project r_roles 表对应的部分实体类对象 package org.example.entity;import lombok.Data;Data public class Role {// 主键 IDprivate Integer id;// 名称private String name;//权限路径private String permission_path; } 创建 r_users 对应的 POJO 对象 User继承自 UserDetails 接口代码如下 package org.example.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails;import java.util.ArrayList; import java.util.Collection; import java.util.List;Data NoArgsConstructor AllArgsConstructor public class User implements UserDetails {//主键 idprivate Integer id;//用户名private String username;//密码private String password;// 状态 1正常2封禁private int status;// 创建时间private int created;private ListRole roles;Overridepublic Collection? extends GrantedAuthority getAuthorities() {ListSimpleGrantedAuthority authorities new ArrayList();for(Role role : roles){authorities.add(new SimpleGrantedAuthority(role.getName()));}return authorities;}Overridepublic String getPassword() {return password;}Overridepublic String getUsername() {return username;}Overridepublic boolean isAccountNonExpired() {return true;}Overridepublic boolean isAccountNonLocked() {return status ! 2;}Overridepublic boolean isCredentialsNonExpired() {return true;}Overridepublic boolean isEnabled() {return status 1;} }Java 类 User 实现了 Spring Security 中的 UserDetails 接口这是因为 Spring Security 需要具体的用户信息来进行认证和授权。通过实现 UserDetails 接口User 类可以与 Spring Security 框架集成允许 Spring Security 使用该类的实例来获取用户的安全相关信息。 getAuthorities()返回授予用户的权限列表。在这个 User 类中它遍历用户的角色列表 roles 并为每个角色创建一个 SimpleGrantedAuthority 对象最终返回权限集合。getPassword()返回用户的密码。在这个 User 类中这个方法返回 User 对象的 password 字段。getUsername()返回用户的用户名。在这个 User 类中这个方法返回 User 对象的 username 字段。isAccountNonExpired()检查用户的账户是否已过期。在这个 User 类中这个方法硬编码返回 true这意味着账户被认为永远不会过期在数据库设计中没有该字段所以默认返回 true。在实际的应用程序中你可能需要添加一些逻辑来判断账户是否真的过期了。isAccountNonLocked()检查用户是否未被锁定返回 false 代表被锁定true 没有被锁定。isCredentialsNonExpired()检查用户证书密码是否未过期。在这个 User 类中这个方法返回 true表明证书永远不会过期。但在实际应用中你可能会根据业务逻辑添加相应的实现代码。isEnabled()检查用户是否被启用。在这个 User 类中如果 status 字段的值为 1代表用户状态正常方法返回 true否则返回 false。 Mapper 的编写如下 package org.example.mapper;import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.example.entity.Role; import org.example.entity.User;import java.util.List;Mapper public interface Usermapper {Select(select * from r_roles as r join r_user_roles as ur on r.id ur.user_id where ur.user_id #{id})ListRole getUserRoleByUserId(Integer id);Select(select * from r_users where username #{username})User getUserByUsername(String username); }UserService 如下 package org.example.service;import org.example.entity.User; import org.example.mapper.Usermapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service;Service public class UserService implements UserDetailsService {Autowiredprivate Usermapper usermapper;Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user usermapper.getUserByUsername(username);if (user null){throw new UsernameNotFoundException(该账户不存在);}//根据 user id 获取用户的角色信息user.setRoles(usermapper.getUserRoleByUserId(user.getId()));return user;} }UserService 类实现了 Spring Security 中的 UserDetailsService 接口这个接口主要用于在认证过程中通过用户名查找用户及其权限。在 loadUserByUsername 方法中你使用了 Usermapper 来获取具体的 User 对象以及相关的角色信息。  为了测试方便编写 controller package org.example.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;RestController public class UserController {GetMapping(/dba/hi)public String dba(){return Hi,dba page;}GetMapping(/user/hi)public String user(){return Hi,user;}GetMapping(/admin/hi)public String admin(){return Hi,admin;}GetMapping(/test/Hi)public String testHi(){return Hi,just for test;} }最后对Spring Security 进行配置编写代码如下  package org.example.config;import org.example.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.access.AccessDeniedHandler;import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {AutowiredUserService userService;AutowiredPasswordEncoder passwordEncoder;BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService).passwordEncoder(passwordEncoder);}Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers(/bda/**).access(hasAnyAuthority(dba,admin,root))//hasAnyRole(dba,admin,root)) 会自动拼接头Role_为头加上对应权限.antMatchers(/admin/**).access(hasAnyAuthority(root,admin))//不会拼接头直接认证。.and().formLogin().loginProcessingUrl(/login)/*.and().anonymous()//未登录才可以访问 permitAll 所有都可以访问*/.and().csrf().disable();http//访问被拒绝走以下.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,AccessDeniedException accessDeniedException)throws IOException, ServletException {// 自定义响应逻辑response.sendRedirect(/access-denied);}});//如果需要跨域使用这里并配置spring WebMVCconfighttp.cors();} }成功  7.多种角色权限认证  有时候一个账号的权限可能是多个如 freejava 即使 admin 又是 dba。那么在配置中可以增加显示权限包含关系的代码可以在 Spring Secuirty 中配置代码如下  BeanRoleHierarchy roleHierarchy(){RoleHierarchyImpl roleHierarchy new RoleHierarchyImpl();String hierarchy ROLE_dba ROLE_user ROLE_admin ROLE_dba;roleHierarchy.setHierarchy(hierarchy);return roleHierarchy;} 该配置生效后具有 ROLE_admin 的角色的用户可以访问所有资源而 ROLE_dba 的角色用户可以访问自身权限的资源和 ROLE_user 的角色的用户资源。  8.自定义权限认证  如果我们不想使用默认提供的权限认证或面对复杂的业务需要时可能需要采取自定义认证方式实现权限认证。 自定义一个类 package org.example.expression;import org.example.entity.Role; import org.example.entity.User; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component;import java.util.ArrayList; import java.util.List;Component(ex) public class U_Define_Expression {public boolean hasAutority(String authority){//获取当前用户的权限Authentication authentication SecurityContextHolder.getContext().getAuthentication();User LoginUser (User) authentication.getPrincipal();ListRole roles LoginUser.getRoles();ListString permissions new ArrayList();for(Role role :roles){permissions.add(role.getName());}//判断用户权限集合中是否存在 authorityreturn permissions.contains(authority);} }在需要使用的 controller 前加上 PreAuthorize(ex.hasAutority(dba)) 表示访问前的验证 补充  HttpSecurity 是 Spring Security 的关键部分用于配置 Web 安全性的详细内容。以下是在 Spring Security 中常用的 HttpSecurity 方法的概览 authorizeRequests()开始请求级安全配置允许你指定 URL 访问规则。 antMatchers(String... antPatterns)使用 Ant 风格的路径模式定义安全限制。 access(String)设置访问特定路径所需的权限表达式。 hasAuthority(String)、hasAnyAuthority(String...)指定用户必须具有的权限以访问特定路径。 hasRole(String)、hasAnyRole(String...)指定用户必须具有的角色才能访问特定路径。这通常自动添加 “ROLE_” 前缀。 formLogin()启用基于表单的身份验证。 loginProcessingUrl(String)定义处理登录请求的 URL。 permitAll()允许所有用户即使未经认证访问使用 antMatchers 定义的路径。 anonymous() 表示可以被未登录的用户即匿名用户访问。 anyRequest()应用于所有剩余的 URL。 authenticated()要求在处理给定的请求之前进行身份验证。 csrf()用于配置 CSRF跨站请求伪造保护。 disable()禁用 csrf 保护或其他配置。 exceptionHandling()配置异常处理。 accessDeniedHandler(AccessDeniedHandler)自定义处理访问被拒绝的情况的策略。 httpBasic()启用 HTTP 基本认证。 logout()配置注销功能。 logoutUrl(String)设置触发注销操作的 URL。 logoutSuccessUrl(String)注销成功后重定向的 URL。 and()用于连接配置使其更易读。 cors()配置跨源资源共享CORS。 headers()配置各种 HTTP 头以增强安全性。 rememberMe()启用记住我的功能。 sessionManagement()配置会话管理。 maximumSessions(int)限制同一用户的并发会话数。 addFilter(Filter filter)添加过滤器在链中对应的还有 Before 和 After 方法。 除了上述方法还有一些专门的配置器可以针对不同的模块来配置 HttpSecurity如 OAuth2, SAML, LDAP 等。 这些 HttpSecurity 方法通常会以链式调用的方式被调用并最终构成一个安全配置顺序定义了整个应用的安全策略。这种方法的组合几乎可以支持所有标准的 Web 安全需求。 总结 Spring Security 是一个功能强大且灵活的框架可帮助开发人员轻松实现应用程序的安全性需求。它提供了丰富的功能和配置选项可以适应各种安全场景和要求。
http://www.yutouwan.com/news/236208/

相关文章:

  • 国际摄影网站企业网站搭建方案
  • 长沙做网站开发价格设计做的好看的网站有哪些
  • 甘肃省建设厅质量投诉网站新闻客户端网站开发
  • 阿里云搭建多个网站陕西住建厅网站官网
  • 莆田网站制作公司wordpress如何制作网站
  • 厦门专业网站推广建站南宁网站排名外包
  • 展示网站模版源码在网站做电子画册
  • 网站建设 seo模块软件生成器下载
  • 静态网站托管平台wordpress ajax json
  • 国外做网站用的程序古色古香 网站模板
  • 做网站的排名苏州园区人才市场
  • 西安论坛网站制作维护怎么做网页投票
  • 网站收录后然后怎么做14亿人口新冠死多少
  • wordpress网站导航龙岩论坛
  • 建筑公司网站新年贺词网站做跳转影响排名吗
  • 微小旅行社能否做网站旅行社网站策划
  • 邢台装修网站建设灵动网站建设
  • 如何建一个网站网站建设误区图
  • 技术网站源码wordpress厦门企业网站设计公司
  • 网站开发的一般流程wordpress编码修改
  • 介绍自己的做的网站嘉兴定制型网站建设
  • wordpress模板 图片站erp系统一般多少钱一年
  • 国外做电商平台的网站有什么网站开发人员没有按照设计开发
  • 最新的高端网站建设wordpress自定义分类模板
  • 怎么根据网站做二维码东莞哪里能学建设网站
  • 游戏网站开发过程开发一个项目的流程
  • 深圳西乡 网站建设益阳市建设局网站是什么
  • 网站开发实施方案进度软件工程很难学吗
  • 建网站公司专业指数基金怎么选
  • 怎么做的网站收录快汽车之家网站系统是什么做的