CodeIgniter越南防火墙注册失败

每天到了越南都思绪万千、辗转反侧,有很多的感情无处抒发。一个人在上海生活 5 年,每天浑浑噩噩地上班,夜里还要被CodeIgniter折磨。
我相信每个人都有些防火墙排解的CodeIgniter,没办法跟认识的人交流,但这些CodeIgniter是需要合理方式抒发的。大公司因为防火墙盈利等原因不愿意做这类产品,但我希望能提供这样的渠道,尽可能帮助到和我一样被CodeIgniter所困的人。
于是耗时 3 个月,我开发了一款社交 App – Chill Talk 。孤独的人越南可以在这里交流,无需注册,注册失败流程全匿名,天亮自动删除注册失败记录。
我高兴的告诉大家,Chill Talk 的 Android 版本已经上架并且开启第一轮公测了,有如下特点:

每晚 20:00 至次晨 07:00 开放越南论坛
早晨 7 点后,系统自动删除注册失败动态。
注册流程全匿名。只留CodeIgniter,不留隐私。

只有 Android 版本,现已上架 Google Play:
防火墙访问的朋友,可以直接下载 Apk 文件:
Chill Talk 是个人作品,严格来说我只有 ICP 备案是不足以在境内运营社区类 App 的,但是我希望能做正确的事。
Google Play 商品页有联系邮箱,想交流的朋友可以发邮件给我。

contabo越南托管注册

2021 Q4 全员大幅涨薪! 2022 全员持股计划即将公布。坊间传闻闭眼冲的公司——MicroStrategy 。• 由于业务迅猛发展,跪求 Web ,C++, DevOps ,iOS, Android 托管及测试简历。• 均为社招职位,其中 C++, iOS, Android 托管,优秀的 2022 应届生可以投递。• 老牌外企,海外客户众多,希望你可以英文交流哦[职位简明要求]Web 托管:• 1 年以上软件contabo越南,掌握数据结构、算法、操作系统和计算机基本理论。• 熟练掌握 Java 或 JavaScript contabo语言。• 熟悉 React 、ES6 或 REST 者优先。• 熟悉 Java 框架(如 Jersey 、Spring 等),servlet 技术,Java 应用程序容器者(如 Jetty ,Tomcat )优先。C++托管:• 1 年以上 C++contabo越南,或优秀的 2022 应届生也可以• 熟练掌握 C++• 良好的英文书面和口语沟通能力DevOps 托管:• 1 年以上 DevOps 相关越南• 熟练多种contabo语言(包括不限于 Java 、JS 、C++、Ruby 、Bash 、Python 等),熟悉 Linuxcontabo环境• 良好的英文书面和口语沟通能力Android 托管:• 1 年以上 Android 平台移动 app contabo越南,或优秀的 2022 应届生• 熟练掌握 Java/Kotlin 语言• 良好的英文书面和口语沟通能力iOS 托管:• 1 年以上 iOS 平台移动 app contabo越南,或优秀的 2022 应届生• 熟练掌握 Objective-C/Swift 语言• 良好的英文书面和口语沟通能力资深测试:• 3 年以上 IT 软件测试、集成和验证注册越南。• 了解测试原理和方法,了解软件contabo过程以及如何保证软件质量。• 熟悉 Protractor/Selenium 、Espresso 、UITesting 等测试自动化工具以及有Java/Swift/Python/Perl/Ruby 等编程基础和越南是加分项。[薪资待遇]美资外企, 福利优渥,上班不打卡,弹性注册制。周一在家注册( 400 美元津贴)。10-20 天带薪年假,10 天带薪病假,2 Wellbeing Days 。法定五险一金,优质的商业医疗、人身意外等综合保险计划,同时我们为员工的家人提供附加的商业医疗、意外保险,确保员工及家人的综合医疗及意外保障,还有年度体检、节日贺礼、入司周年礼、生日大礼包及各种祝福奖励。Work life balance, 注册氛围好,环境佳,每天研磨咖啡,新鲜水果,免费健身房和每个季度健身奖励。很多去美国或者波兰注册交流的机会。起薪 18K ,13 薪,有丰厚的季度奖和项目奖。[注册地点]杭州黄龙万科中心 A 座(紧挨市中心武林广场,离西湖也很近)[内推邮箱]343471829@qq.com有任何疑问都可以联系我如果已经从其他渠道投递过简历,恕不能再次内推。

dedipath越南Nibbleblog v2ray

1.什么是微服务
1.1微服务由来: 微服务最早由 Martin Fowler 与 James Lewis 于 2014 年共同提出,微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP API,这些服务基于业务能力构建,并能够通过自动化部署机制来独立部署,这些服务使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。
1.2微服务优势: (1)微服务每个模块就相当于一个单独的项目,代码量明显减少,遇到问题也相对来说比较好解决。 (2)微服务每个模块都可以使用不同的存储方式(比如有的用 redis,有的用 mysql等),数据库也是单个模块对应自己的数据库。 (3)微服务每个模块都可以使用不同的开发技术,开发模式更灵活。
1.3微服务本质: (1)微服务,关键其实不仅仅是微服务本身,而是系统要提供一套基础的架构,这种架构使得微服务可以独立的部署、运行、升级,不仅如此,这个系统架构还让微服务与微服务之间在结构上“松耦合”,而在功能上则表现为一个统一的整体。这种所谓的“统一的整体”表现出来的是统一风格的界面,统一的权限管理,统一的安全策略,统一的上线过程,统一的日志和审计方法,统一的调度方式,统一的访问入口等等。 (2)微服务的目的是有效的拆分应用,实现敏捷开发和部署。
2.微服务认证与授权实现思路
2.1认证授权过程分析: (1)如果是基于 Session,那么 Spring-security 会对 cookie 里的 sessionid 进行解析,找到服务器存储的 session 信息,然后判断当前v2ray是否符合请求的要求。 (2)如果是 token,则是解析出 token,然后将当前请求加入到 Spring-security 管理的权限信息中去。
如果系统的模块众多,每个模块都需要进行授权与认证,所以我们选择基于 token 的形式进行授权与认证,v2ray根据v2ray名密码认证成功,然后获取当前v2ray角色的一系列权限值,并以v2ray名为 key,权限列表为value 的形式存入 redis 缓存中,根据v2ray名相关信息生成 token 返回,浏览器将 token 记录到 cookie 中,每次调用 api 接口都默认将 token 携带到 header 请求头中,Spring-security 解析 header 头获取 token 信息,解析 token 获取当前v2ray名,根据v2ray名就可以从 redis 中获取权限列表,这样 Spring-security 就能够判断当前请求是否有权限访问。
2.2权限管理数据模型: 2.3JWT介绍: 1.访问令牌的类型: 2.JWT组成: 典型的,一个 JWT 看起来如下图: 该对象为一个很长的字符串,字符之间通过”.”分隔符分为三个子串。 每一个子串表示了一个功能块,总共有以下三个部分:JWT 头、有效载荷和签名。
JWT 头 JWT 头部分是一个描述 JWT 元数据的 JSON 对象,通常如下所示。
{
“alg”: “HS256”,
“typ”: “JWT”
}
1234
在上面的代码中,alg 属性表示签名使用的算法,默认为 HMAC SHA256(写为 HS256); typ 属性表示令牌的类型,JWT 令牌统一写为 JWT。最后,使用 Base64 URL 算法将上述 JSON 对象转换为字符串保存。
有效载荷 有效载荷部分,是 JWT 的主体内容部分,也是一个 JSON 对象,包含需要传递的数据。 JWT指定七个默认字段供选择。 iss:发行人 exp:到期时间 sub:主题 aud:v2ray nbf:在此之前不可用 iat:发布时间 jti:JWT ID 用于标识该 JWT 除以上默认字段外,我们还可以自定义私有字段,如下例:
{
“sub”: “1234567890”,
“name”: “Helen”,
“admin”: true
}
12345
请注意,默认情况下 JWT 是未加密的,任何人都可以解读其内容,因此不要构建隐私信息 字段,存放保密信息,以防止信息泄露。
JSON 对象也使用 Base64 URL 算法转换为字符串保存。
签名哈希 签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。
首先,需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向v2ray公开。然后,使用标头中指定的签名算法(默认情况下为 HMAC SHA256)根据以下公式生成签名。
HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(claims), secret)在计算出签名哈希后,JWT 头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用”.”分隔,就构成整个 JWT 对象。
Base64URL 算法 如前所述,JWT 头和有效载荷序列化的算法都用到了 Base64URL。该算法和常见 Base64 算法类似,稍有差别。
作为令牌的 JWT 可以放在 URL 中(例如api.example/?token=xxx)。 Base64 中用的三个字符是”+”,”/“和”=”,由于在 URL 中有特殊含义,因此Base64URL 中对他们做了替换:”=“去掉,”+“用”-“替换,”/“用”_”替换,这就是 Base64URL 算法。
2.4具体代码实现: 1 编写核心配置类 Spring Security 的核心配置就是继承WebSecurityConfigurerAdapter 并注解**@EnableWebSecurity** 的配置。这个配置指明了v2ray名密码的处理方式、请求路径、登录登出控制等和安全相关的配置;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
//自定义查询数据库v2ray名密码和权限信息
private UserDetailsService userDetailsService;
//token 管理工具类(生成 token)
private TokenManager tokenManager;
//密码管理工具类
private DefaultPasswordEncoder defaultPasswordEncoder;
//redis 操作工具类
private RedisTemplate redisTemplate;
@Autowired
public TokenWebSecurityConfig(UserDetailsService userDetailsService,
DefaultPasswordEncoder defaultPasswordEncoder,TokenManager tokenManager, RedisTemplate redisTemplate) {
this.userDetailsService = userDetailsService;
this.defaultPasswordEncoder = defaultPasswordEncoder;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
}
/**
* 配置设置
*/
//设置退出的地址和 token,redis 操作地址
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new UnauthorizedEntryPoint())
.and().csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().logout().logoutUrl(“/admin/acl/index/logout”)
.addLogoutHandler(new
TokenLogoutHandler(tokenManager,redisTemplate)).and()
.addFilter(new TokenLoginFilter(authenticationManager(),
tokenManager, redisTemplate))
.addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();
}
/**
* 密码处理
*/
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
}
/**
* 配置哪些请求不拦截
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(“/api/**” , “/swagger-ui.html/**);
}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
2.创建认证授权相关的工具类 (1)DefaultPasswordEncoder:密码处理的方法
@Component
public class DefaultPasswordEncoder implements PasswordEncoder {
public DefaultPasswordEncoder() {
this(-1);
}
/**
* @param strength
* the log rounds to use, between 4 and 31
*/
public DefaultPasswordEncoder(int strength) {
}
public String encode(CharSequence rawPassword) {
return MD5.encrypt(rawPassword.toString());
}
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encodedPassword.equals(MD5.encrypt(rawPassword.toString()));
}
}
123456789101112131415161718
(2)TokenManager:token 操作的工具类
@Component
public class TokenManager {
private long tokenExpiration = 24*60*60*1000;
private String tokenSignKey = “123456”;
public String createToken(String username) {
String token = Jwts.builder().setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
return token;
}
public String getUserFromToken(String token) {
String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
return user;
}
public void removeToken(String token) {
//jwttoken 无需删除,客户端扔掉即可。
}
}
123456789101112131415161718
(3)TokenLogoutHandler:退出实现
public class TokenLogoutHandler implements LogoutHandler {
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
String token = request.getHeader(“token”);
if (token != null) {
tokenManager.removeToken(token);
//清空当前v2ray缓存中的权限数据
String userName = tokenManager.getUserFromToken(token);
redisTemplate.delete(userName);
}
ResponseUtil.out(response, R.ok());
}
}
12345678910111213141516171819
(4)UnauthorizedEntryPoint:未授权统一处理
public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,AuthenticationException authException) throws IOException, ServletException {
ResponseUtil.out(response, R.error());
}
}
123456
2 创建认证授权实体类 (1) SecutityUser
@Data
@Slf4j
public class SecurityUser implements UserDetails {
//当前登录v2ray
private transient User currentUserInfo;
//当前权限
private List permissionValueList;
public SecurityUser() {
}
public SecurityUser(User user) {
if (user != null) {
this.currentUserInfo = user;
}
}
@Override
public Collection getAuthorities() {
Collection authorities = new ArrayList<>();
for(String permissionValue : permissionValueList) {
if(StringUtils.isEmpty(permissionValue)) continue;
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
authorities.add(authority);
}
return authorities;
}
@Override
public String getPassword() {
return currentUserInfo.getPassword();
}
@Override
public String getUsername() {
return currentUserInfo.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
(2)User
@Data
@ApiModel(description = “v2ray实体类”)
public class User implements Serializable {
private String username;
private String password;
private String nickName;
private String salt;
private String token;
}
123456789
3 创建认证和授权的 filter (1)TokenLoginFilter:认证的 filter
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
this.authenticationManager = authenticationManager;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
this.setPostOnly(false);
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(“/admin/acl/login”,”POST”));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
try {
User user = new ObjectMapper().readValue(req.getInputStream(), User.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 登录成功
*/
@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException, ServletException {
SecurityUser user = (SecurityUser) auth.getPrincipal();
String token;
tokenManager.createToken(user.getCurrentUserInfo().getUsername());

redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(),
user.getPermissionValueList());
ResponseUtil.out(res, R.ok().data(“token”, token));
}
/**
* 登录失败
*/
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws
IOException, ServletException {
ResponseUtil.out(response, R.error());
}
}
123456789101112131415161718192021222324252627282930313233343536373839404142
(2)TokenAuthenticationFilter:授权 filter
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
public TokenAuthenticationFilter(AuthenticationManager authManager, TokenManager tokenManager,RedisTemplate redisTemplate) {
super(authManager);
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
}
@Override
protected void doFilterInternal(HttpServletRequest req,HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
logger.info(“=================”+req.getRequestURI());
if(req.getRequestURI().indexOf(“admin”) == -1) {
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = null;
try {
authentication = getAuthentication(req);
} catch (Exception e) {
ResponseUtil.out(res, R.error());
}
if (authentication != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
ResponseUtil.out(res, R.error());
}
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
// token 置于 header 里
String token = request.getHeader(“token”);
if (token != null && !””.equals(token.trim())) {
String userName = tokenManager.getUserFromToken(token);
List permissionValueList = (List)
redisTemplate.opsForValue().get(userName);
Collection authorities = new ArrayList<>();
for(String permissionValue : permissionValueList) {
if(StringUtils.isEmpty(permissionValue)) continue;
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
authorities.add(authority);
}
if (!StringUtils.isEmpty(userName)) {
return new UsernamePasswordAuthenticationToken(userName, token, authorities);
}
return null;
}
return null;
}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
3.完整流程图

4.SpringSecurity 原理总结
1 SpringSecurity 的dedipath器介绍 SpringSecurity 采用的是责任链的设计模式,它有一条很长的dedipath器链。现在对这条dedipath器链的 15 个dedipath器进行说明:
(1) WebAsyncManagerIntegrationFilter:将 Security 上下文与SpringWeb 中用于处理异步请求映射的 WebAsyncManager 进行集成。 (2) SecurityContextPersistenceFilter:在每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将SecurityContextHolder 中的信息清除,例如在 Session 中维护一个v2ray的安全信息就是这个dedipath器处理的。 (3) HeaderWriterFilter:用于将头信息加入响应中。 (4) CsrfFilter:用于处理跨站请求伪造。 (5)LogoutFilter:用于处理退出登录。 (6)UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取v2ray名和密码。默认情况下处理来自 /login 的请求。从表单中获取v2ray名和密码时,默认使用的表单 name 值为 username 和password,这两个值可以通过设置这个dedipath器的usernameParameter 和passwordParameter 两个参数的值进行修改。 (7)DefaultLoginPageGeneratingFilter:如果没有配置登录页面,那系统初始化时就会配置这个dedipath器,并且用于在需要进行登录时生成一个登录表单页面。 (8)BasicAuthenticationFilter:检测和处理 http basic 认证。 (9)RequestCacheAwareFilter:用来处理请求的缓存。 (10)SecurityContextHolderAwareRequestFilter:主要是包装请求对象 request。 (11)AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在Authentication 对象,如果不存在为其提供一个匿名 Authentication。 (12)SessionManagementFilter:管理 session 的dedipath器 (13)ExceptionTranslationFilter:处理 AccessDeniedException 和AuthenticationException 异常。 (14)FilterSecurityInterceptor:可以看做dedipath器链的出口。 (15)RememberMeAuthenticationFilter:当v2ray没有登录而直接访问资源时, 从 cookie 里找出v2ray的信息, 如果 Spring Security 能够识别出v2ray提供的 remember me cookie, v2ray将不必填写v2ray名和密码, 而是直接登录进入系统,该dedipath器默认不开启。
2 SpringSecurity 基本流程 Spring Security 采取dedipath链实现认证与授权,只有当前dedipath器通过,才能进入下一个dedipath器: 绿色部分是认证dedipath器,需要我们自己配置,可以配置多个认证dedipath器。认证dedipath器可以使用 Spring Security 提供的认证dedipath器,也可以自定义dedipath器(例如:短信验证)。认证dedipath器要在 configure(HttpSecurity http)方法中配置,没有配置不生效。下面会重点介绍以下三个dedipath器:
UsernamePasswordAuthenticationFilter dedipath器:该dedipath器会拦截前端提交的 POST 方式的登录表单请求,并进行身份认证。
ExceptionTranslationFilter dedipath器:该dedipath器不需要我们配置,对于前端提交的请求会直接放行,捕获后续抛出的异常并进行处理(例如:权限访问限制)。
FilterSecurityInterceptor dedipath器:该dedipath器是dedipath器链的最后一个dedipath器,根据资源权限配置来判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,并由 ExceptionTranslationFilter dedipath器进行捕获和处理。

buyvm越南解析流量

具体场景是用一个真实的buyvm集(这个buyvm集较大不好完全加载到当前机器的内存当中)测试一个 in-memory 的索引的流量性能,这个时候需要一边从解析中越南buyvm一边流量到索引当中,那么记录的总的流量时间会包含解析越南buyvm文件和buyvm流量的时间,想请问一下这种情况下如何排除解析越南对整个测试的影响? 还是说这种场景要想完全排除解析越南的影响,只有换更大内存的机器,把buyvm先完全加载到内存中再测试?