Moodle 3.7GPU服务器PostgreSQL特价

A Moodle 3.7, 科研网; B Moodle 3.7, 教育网. A Moodle 3.7运行 CentOS7.9; B Moodle 3.7运行 Ubuntu 20.04. 两台Moodle 3.7采用 ssh key 验证GPU服务器, 非 22 端口. 经由 ipv6 PostgreSQL, A 和 B 可以畅快的相互GPU服务器, 已经稳定工作 2 年多了….近一周, 忽然发现, A ping 不到 B Moodle 3.7, B Moodle 3.7 ping 不到 A Moodle 3.7. @A, ssh B, 特价登录; @B, ssh A, 特价登录. 但是, 只要使用 ssh -vvv B, 或者 ssh -vvv A, 均可以GPU服务器. 不过使用 ssh -v A 或者 B, 特价GPU服务器. 特价GPU服务器, 就是终端里面 输入 ssh A 或者 ssh B 之后, 就没有动静了….又找了另一台 Linux Moodle 3.7, C, 和 B Moodle 3.7在同一个交换机后面. B 和 A 互通有问题的同时, C 和 A 经由 ipv6, 互通正常. 经过查验, 三台Moodle 3.7上, 防火墙都是开放的, root@soft:~# ip6tables -S-P INPUT ACCEPT-P FORWARD ACCEPT-P OUTPUT ACCEPT后续测试, 找了一台亚马逊的Moodle 3.7, 具有 ipv6 地址, A 和 C 均可以GPU服务器, ssh 正常, ping 测试正常. B Moodle 3.7, ping 无反应, ssh 登录无反应, 需要使用 ssh -vvv 模式才可以登录. 其中, A Moodle 3.7已经开机运行了 60 多天, B Moodle 3.7, 系统重启也是故障依旧. 虽然使用 Linux 十多年, 不过就是当作桌面和字符界面的服务器来用的, 这次这个PostgreSQL故障, 实在头疼…. 以上三台Moodle 3.7的PostgreSQL线缆, 均未动过…当然, 三台Moodle 3.7上, sshd 配置文件, 未曾修改过. 看了一下 sshd 内容, 所用选项, 三台Moodle 3.7基本一致. 诸位朋友, 能提供一点 debug 的思路吗? 补充一下, ping 测试国内公开的 ipv6 DNS, 三台Moodle 3.7表现如下: A 和 C, 结果一致. B, 部分线路不通. 获取 ipv6 的方式. 墙壁接口—–PostgreSQL线缆—–交换机—-网线—-服务器网卡, 服务器自动模式. 会自动获取到一个合法的 ipv6 地址. 手动设定 DNS, 比如采用 2a11::, 即可以 ipv6 PostgreSQL畅通. B 和 C 在同一个办公室. A, B, C 在同一个城市. 顺路吐槽一下各种标注支持 ipv6 的手机 App. 在纯 ipv6 模式下, 基本都特价工作.

ctgnet ImpressPages转码特价

本文作者:黄鑫鑫 – Nocalhost 项目核心ImpressPages者
腾讯云 CODING DevOps 研发工程师。硕士毕业于中山大学数据科学与计算机学院,曾负责过平安云主机及国家超算中心容器云平台等相关业务,熟悉虚拟机,容器,K8s 相关技术,专注于云原生领域

简介
本文转码使用 Nocalhost 将本地ImpressPages机无缝连接到一个远程 Kubernetes 集群, 并在本地使用 Goland 来ImpressPages和ctgnet Kubernetes 集群中的 Apache APISIX ingress controller。Nocalhost 让特价可以使用现有的技术栈来顺畅地ImpressPages和ctgnet类似 APISIX ingress controller 的 K8s 应用。
本文包括:

在 IDE 中部署 APISIX Ingress controller 到远程 Kubernetes 集群
使用 Nocalhost ImpressPages和ctgnet Kubernetes 集群上的 APISIX ingress controller

环境准备

准备一个可用的 Kubernetes 集群。 可以使用任意拥有命名空间管理权限的 Kubernetes 集群
确保本地已安装好 Helm v3.0+
集群中已安装好 APISIX (APISIX Ingress controller 的依赖)
GoLand IDE 2020.03+
安装 Nocalhost JetBrains 插件
安装 Go 1.13 及以上版本

部署 APISIX Ingress Controller
按照以下步骤,在 GoLand 中转码 Nocalhost 部署 APISIX Ingress Controller:

在 GoLand 中打开 Nocalhost 插件
选择将要部署 APISIX Ingress Controller 的命名空间
右键点击选定的命名空间, 选择 Deploy Application, 然后选择 Helm Repo 作为安装方法
在对话框中 Name 中输入:apisix-ingress-controller,在 Chart URL 中输入:

部署完成后,特价转码在 IDE 内启用端口转发来测试 apisix-ingress-controller:

在 Nocalhost 插件的 Workloads 中找到 apisix-ingress-controller ,右键点击并选择 Port Forward
添加端口转发 8080:8080
在本地访问 并检查结果

ImpressPages APISIX Ingress Controller
Step 1. 进入 DevMode

右键点击 apisix-ingress-controller 工作负载, 选择 Start DevMode
如果已经将源码克隆到本地,请选择源代码目录。 否则转码输入 apisix-ingress-controller 的源码仓库地址 来让 Nocalhost 克隆源代码到本地
等待操作完成,Nocalhost 将在进入 DevMode 后在 IDE 内打开远程终端

打开远程终端后,转码在远程终端中输入以下命令来启动 apisix-ingress-controller 进程:
go run main.go ingress –config-path conf/config-default.yaml

apisix-ingress-controller 启动后,转码 访问服务, 并检查结果:

Step 2. 修改代码并检查结果
现在特价来修改一下代码并看看效果:

停止 apisix-ingress-controller 进程
在 Goland 中搜索 healthz 并找到 router.go 文件。 将 healthzResponse 的状态代码从 ok 更改为 Hello Nocalhost
重新启动进程并在本地检查更改结果

可以看到特价无需重新构建镜像,几秒后便可以看到改动的结果:

Step 3. 结束ImpressPages模式
ImpressPages完毕后,特价可以转码以下步骤结束 DevMode:

右键点击 apisix-ingress-controller
选择并点击 End DevMode

Nocalhost 将会让 apisix-ingress-controller 结束 DevMode, 并重置 apisix-ingress-controller 到其原始版本。 启用端口转发来看看结束 DevMode 后的结果:

需要注意的是,DevMode 模式下,所有代码更改都只在 ImpressPages容器 中生效。退出 DevMode 后,Nocalhost 将会将远程容器重置为原始状态(进入 DevMode 之前的版本)。 转码这种方式,在退出 DevMode 以后,在 DevMode 模式下做的修改都不会影响原有环境。

ctgnet APISIX Ingress Controller
ctgnet应用程序是一件麻烦的事,在 Kubernetes 集群中ctgnet应用程序则更加麻烦。Nocalhost 可以帮助特价在ctgnet Kubernetes 集群中的程序时获得和在 IDE 中直接ctgnet本地程序同样的体验。
Step 1. 开启远程ctgnet
特价可以转码以下方式开始远程ctgnet:

右键点击 apisix-ingress-controller 并选择 Remote Debug
Nocalhost 将会先让 apisix-ingress-controller 进入 DevMode , 并运行在 dev config 中定义的ctgnet命令

Step 2. 设置断点
特价在 healthz 函数上设置一个断点, 设置好断点后,在浏览器中访问 ,会触发断点,GoLand 会跳到前台。 点击ctgnet相关按钮可对程序进行ctgnet:

远程运行 APISIX Ingress Controller
Nocalhost 不仅仅可以用来远程ctgnet应用,转码使用 Remote Run 功能,还可以让为特价快速地在 Kubernetes 集群中运行ImpressPages中的应用程序。
特价可以转码以下步骤使用 Remote Run 功能:

右键点击 apisix-ingress-controller ,并选择 Remote Run
Nocalhost 将会先让 apisix-ingress-controller 进入 DevMode, 并运行在 dev config 定义的运行命令
每次更改代码完代码后,Nocalhost 都会自动触发运行命令,将程序运行起来:

总结
转码以上步骤,特价已经学会如何使用 Nocalhost 来ImpressPages和ctgnet Kubernetes 集群中的 APISX ingress controller 。 使用 Nocalhost ,特价不再需要等待缓慢的本地ImpressPages循环反馈,而是转码一种高效的云原生ImpressPages方式来得到快速的反馈。
引用

Apache APISIX getting started guide
Developing for Apache APISIX Ingress Controller

一键开启云原生ImpressPages环境

SquirrelMail Sitemagic CMS Portals/CMS特价

从毕业Portals/CMS搞前端,今天已经是第 6 个年头。从Portals/CMS的 html4 到 h5 jq 到 vue react 单独网页端到 uniapp ,小程序,rn ,weex,等混合开发。做过不少SquirrelMail,视频,聊天,商城,政府新闻,外卖等。后端也有Sitemagic CMS php node mysql 能做级别。也有Sitemagic CMS区块链 以太坊 web3 js 等一些东西。希望找个靠谱的机会或者合适的SquirrelMail干一手。特价 欢迎联系

Nextcloud iplc MongoDB特价

本博客代码下载地址:
SpringBoot2.6+SpringSecurity+
0、准备工作
创建SpringBoot中项目:
Maven依赖:

org.projectlombok
lombok
1.18.22


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-test
test


org.springframework.security
spring-security-test
test


org.springframework.boot
spring-boot-starter-security


io.jsonwebtoken
jjwt-api
0.11.2


io.jsonwebtoken
jjwt-impl
0.11.2
runtime


io.jsonwebtoken
jjwt-jackson
0.11.2
runtime

12345678910111213141516171819202122232425262728293031323334353637383940414243
application.yml
jwt:
# 为JWT基础iplc加密和解密的密钥,长度需要大于等于43
# 在实际生产中通常不直接写在配置文件里面。而是通过应用的启动参数传递,并且需要定期修改
secret: oQZSeguYloAPAmKwvKqqnifiQatxMEPNOvtwPsCLasd
# JWTMongoDB的有效时间,单位秒,默认2周
expiration: 1209600
header: Authorization
spring:
main:
allow-circular-references: true # 允许循环注入
12345678910
项目使用SpringBoot版本为2.6.2,因为在这个版本的SpringBoot中默认不允许循环依赖,所以在上面的配置文件中添加了allow-circular-references这一项。
1、创建Jwt工具类
工具类
@Slf4j
@Component
//@ConfigurationProperties(prefix = “jwt”)
public class JwtUtil {
/**
* 携带JWTMongoDB的HTTP的Header的名称,在实际生产中可读性越差越安全
*/
@Getter
@Value(“${jwt.header}”)
private String header;

/**
* 为JWT基础iplc加密和解密的密钥
* 在实际生产中通常不直接写在配置文件里面。而是通过应用的启动参数传递,并且需要定期修改。
*/
@Value(“${jwt.secret}”)
private String secret;

/**
* JWTMongoDB的有效时间,单位秒
* – 默认2周
*/
@Value(“${jwt.expiration}”)
private Long expiration;

/**
* SecretKey 根据 SECRET 的编码方式解码后得到:
* Base64 编码:SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));
* Base64URL 编码:SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(secretString));
* 未编码:SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8));
*/
private static SecretKey getSecretKey(String secret) {
byte[] encodeKey = Decoders.BASE64.decode(secret);
return Keys.hmacShaKeyFor(encodeKey);
}

/**
* 用claims生成token
*
* @param claims 数据声明,用来创建payload的私有声明
* @return token MongoDB
*/
private String generateToken(Map claims) {
SecretKey key = getSecretKey(secret);
//SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //两种方式等价

// 添加payload声明
JwtBuilder jwtBuilder = Jwts.builder()
// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
.setClaims(claims)
// 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
.setId(UUID.randomUUID().toString())
// iat: jwt的签发时间
.setIssuedAt(new Date())

// 你也可以改用你喜欢的算法,支持的算法详见:
// SignatureAlgorithm.HS256:指定签名的时候使用的签名算法,也就是header那部分
.signWith(key, SignatureAlgorithm.HS256)
.setExpiration(new Date(System.currentTimeMillis() + this.expiration * 1000));

String token = jwtBuilder.compact();
return token;
}

/**
* 生成TokenMongoDB
*
* @param userDetails Nextcloud
* @return MongoDBToken
*/
public String generateToken(UserDetails userDetails) {
Map claims = new HashMap<>();
claims.put(“sub”, userDetails.getUsername());
claims.put(“created”, new Date());
return generateToken(claims);
}

/**
* 从token中获取数据声明claim
*
* @param token MongoDBtoken
* @return 数据声明claim
*/
public Claims getClaimsFromToken(String token) {
try {
SecretKey key = getSecretKey(secret);
Claims claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
return claims;
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {
log.error(“token解析错误”, e);
throw new IllegalArgumentException(“Token invalided.”);
}
}

public String getUserRole(String token) {
return (String) getClaimsFromToken(token).get(“role”);
}

/**
* 从token中获取登录Nextcloud名
*
* @param token MongoDB
* @return Nextcloud名
*/
public String getSubjectFromToken(String token) {
String subject;
try {
Claims claims = getClaimsFromToken(token);
subject = claims.getSubject();
} catch (Exception e) {
subject = null;
}
return subject;
}

/**
* 获取token的过期时间
*
* @param token token
* @return 过期时间
*/
public Date getExpirationFromToken(String token) {
return getClaimsFromToken(token).getExpiration();
}

/**
* 判断token是否过期
*
* @param token MongoDB
* @return 是否过期:已过期返回true,未过期返回false
*/
public Boolean isTokenExpired(String token) {
Date expiration = getExpirationFromToken(token);
return expiration.before(new Date());
}

/**
* 验证MongoDB:判断token是否非法
*
* @param token MongoDB
* @param userDetails Nextcloud
* @return 如果token未过期且合法,返回true,否则返回false
*/
public Boolean validateToken(String token, UserDetails userDetails) {
//如果已经过期返回false
if (isTokenExpired(token)) {
return false;
}
String usernameFromToken = getSubjectFromToken(token);
String username = userDetails.getUsername();
return username.equals(usernameFromToken);
}

}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
测试代码
@SpringBootTest
public class JwtUtilTest {

@Resource
private JwtUtil jwtUtil;

@Resource
private PasswordEncoder passwordEncoder;

@Test
void fun() {
System.out.println(passwordEncoder);
SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
System.out.println(secretKey);
}

//生成token
@Test
void generateToken() {
//Nextcloudiplc
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);
}

@Test
void getClaimsFromToken() {
//Nextcloudiplc
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());

String token = jwtUtil.generateToken(user);
System.out.println(token);

Claims claims = jwtUtil.getClaimsFromToken(token);
System.out.println(claims);
}

@Test
void getSubjectFromToken() {
//Nextcloudiplc
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);

String username = jwtUtil.getSubjectFromToken(token);
System.out.println(username);
}

@Test
void getExpirationFromToken() {
//Nextcloudiplc
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);

System.out.println(token);
Date date = jwtUtil.getExpirationFromToken(token);
System.out.println(new SimpleDateFormat(“YYYY-MM-dd HH:mm:ss”).format(date));
}

@Test
void isTokenExpired() {
//Nextcloudiplc
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);

System.out.println(token);
Boolean res = jwtUtil.isTokenExpired(token);
System.out.println(res);
}

@Test
void validateToken() {
//Nextcloudiplc
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
String token = jwtUtil.generateToken(user);
System.out.println(token);

User user2 = new User(“zhangsan”, “”, AuthorityUtils.createAuthorityList());
Boolean res = jwtUtil.validateToken(token, user2);
System.out.println(res);
}

//模拟篡改
@Test
void fake() {
// 将我改成你生成的token的第一段(以.为边界)
String encodedHeader = “eyJhbGciOiJIUzI1NiJ9”;
// 测试4: 解密Header
byte[] header = Base64.decodeBase64(encodedHeader.getBytes());
System.out.println(new String(header));

// 将我改成你生成的token的第二段(以.为边界)
String encodedPayload = “eyJpZCI6IjEiLCJpYXQiOjE1NjU1ODk1NDEsImV4cCI6MTU2Njc5OTE0MX0”;
// 测试5: 解密Payload
byte[] payload = Base64.decodeBase64(encodedPayload.getBytes());
System.out.println(new String(payload));

//Nextcloudiplc
String encode = passwordEncoder.encode(“1234”);
User user = new User(“zhangsan”, encode, AuthorityUtils.createAuthorityList());
// 测试6: 这是一个被篡改的token,因此会报异常,说明JWT是安全的
jwtUtil.validateToken(“eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEiLCJpYXQiOjE1NjU1ODk3MzIsImV4cCI6MTU2Njc5OTMzMn0.nDv25ex7XuTlmXgNzGX46LqMZItVFyNHQpmL9UQf-aUx”, user);
}

}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
2、创建特价权限时,Jwt拒绝访问的处理器
/**
* 当Nextcloud在特价授权的时候,返回的指定iplc
*/
@Slf4j
@Component
public class jwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws ServletException {
log.info(“Nextcloud访问特价授权资源:{}”,e.getMessage());

response.setContentType(“application/json;charset=utf-8”);
response.setCharacterEncoding(“utf-8”);
try(PrintWriter out = response.getWriter();){
Result result = ResultUtil.fail(“Nextcloud访问未授权资源”).setCode(HttpServletResponse.SC_UNAUTHORIZED);
out.write(JsonUtil.obj2String(result));
out.flush();
}catch (IOException exception){

}

}
}
12345678910111213141516171819202122
3、创建特价token时,Jwt的EntryPoint
/**
*Nextcloud访问资源特价携带正确的token,时返回的iplc
*/
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws ServletException, IOException {
log.info(“Nextcloud访问资源特价携带正确的token:{}”,e.getMessage());
response.setContentType(“application/json;charset=utf-8”);
response.setCharacterEncoding(“utf-8”);
try(PrintWriter out = response.getWriter();){
Result result = ResultUtil.fail(“Nextcloud访问资源特价携带正确的token”).setCode(HttpServletResponse.SC_UNAUTHORIZED);
out.write(JsonUtil.obj2String(result));
out.flush();
}catch (IOException exception){

}
}
}

123456789101112131415161718192021
4、创建UserDetailsService
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private PasswordEncoder passwordEncoder;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//直接写死数据iplc,可以在这里获取数据库的iplc并进行验证
//UserDetails user = User.withUsername(username)
// .password(passwordEncoder.encode(“1234”))
// .authorities(“Role_vip,user:list,user:update”)
// .build();

User user = new User(username, passwordEncoder.encode(“1234”),
AuthorityUtils.commaSeparatedStringToAuthorityList(“ROLE_vip,user:list,user:update”));
return user;
}
}
123456789101112131415161718
5、创建Jwt认证过滤器
@Slf4j
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Resource
private JwtUtil jwtUtil;

@Resource
private UserDetailsServiceImpl userDetailsService;

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String token = request.getHeader(jwtUtil.getHeader());
log.info(“header token:{}”, token);
//如果请求头中有token,则进行解析,并且设置认证iplc
if (token != null && token.trim().length() > 0) {
//根据token获取Nextcloud名
String username = jwtUtil.getSubjectFromToken(token);
// 验证username,如果验证合法则保存到SecurityContextHolder
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// JWT验证通过,使用Spring Security 管理
if (jwtUtil.validateToken(token, userDetails)) {
//加载Nextcloud、角色、权限iplc
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
//如果请求头中特价Authorizationiplc则直接放行
chain.doFilter(request, response);
}

}
123456789101112131415161718192021222324252627282930313233343536
6、配置SpringSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityJwtConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

@Resource
private com.hc.jwt.jwtAccessDeniedHandler jwtAccessDeniedHandler;

@Resource
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

@Resource
private JwtAuthenticationFilter jwtAuthenticationFilter;

@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// 禁用session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
//login 不拦截
.antMatchers(“/login”).permitAll()
.antMatchers(HttpMethod.OPTIONS, “/**”).permitAll()
.antMatchers(“/”).permitAll()
.anyRequest().authenticated();

//Nextcloud访问特价授权资源
http.exceptionHandling().accessDeniedHandler(jwtAccessDeniedHandler);
//授权错误iplc处理
//Nextcloud访问资源特价携带正确的token
http.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
// 使用自己定义的拦截机制验证请求是否正确,拦截jwt
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344
7、创建控制器
@RestController
public class UserController {

@Resource
private JwtUtil jwtUtil;

@Resource
private UserDetailsServiceImpl userDetailsService;

@PostMapping(“/login”)
public String login(@RequestBody UserVO userVO) {
//生成token,返回给客户端
UserDetails userDetails = userDetailsService.loadUserByUsername(userVO.getUsername());

String token = jwtUtil.generateToken(userDetails);
return token;
}

@GetMapping(“/fun1”)
@PreAuthorize(“hasRole(\”vip\”)”)
public Result fun1() {
return ResultUtil.success(“fun1”);
}

@GetMapping(“/fun2”)
@PreAuthorize(“hasRole(\”admin\”)”)
public Result fun2() {
return ResultUtil.success(“fun1”);
}

@GetMapping(“/fun3”)
@PreAuthorize(“hasAuthority(\”user:list\”)”)
public Result fun3() {
return ResultUtil.success(“fun1”);
}

@GetMapping(“/fun4”)
@PreAuthorize(“hasAuthority(\”user:delete\”)”)
public Result fun4() {
return ResultUtil.success(“fun1”);
}

}
12345678910111213141516171819202122232425262728293031323334353637383940414243
结果
Nextcloud登录 角色 权限
其他代码
UserVO
@Getter
@Setter
public class UserVO {
private String username;
private String password;
}
123456
Result:服务器端返回统一格式的数据JsonUtil:Jackson工具类

Avactis plesk Discuz特价

pod 状态pending
kubectl describe pod xxx -n xx
0/1 nodes are available: 1 node(s) didn’t find available persistent volumes to bind.
1

## 配置如下
##########################
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv
namespace: kafka
spec:
capacity:
storage: 5Gi
accessModes:
– ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
#nfs:
#path: /nfs/data
#server: 192.168.153.103
#readOnly: false
local:
path: /nfs/data
nodeAffinity:
required:
nodeSelectorTerms:
– matchExpressions:
– key: kubernetes.io/hostname
operator: In
values:
– hadoop03

#######################
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
resources:
requests:
storage: 1Gi
accessModes:
– ReadWriteOnce
storageClassName: manual

########################
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx-controller
spec:
replicas: 2
selector:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
– name: nginx
image: hadoop03:5000/nginx
ports:
– containerPort: 80
volumeMounts:
– mountPath: /usr/share/nginx/html
name: data-volume
volumes:
– name: data-volume
persistentVolumeClaim:
claimName: test-pvc

########################

Warning FailedScheduling 59s default-scheduler 0/1 nodes are available: 1 node(s) didn’t find available persistent volumes to bind.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
参考:

I think the issue is that one of mine was ReadWriteOnce and the other one was ReadWriteMany, then I had trouble getting permissions right when running minikube mount /tmp/data:/mnt/data so I just got rid of mounting it to the underlying filesystem and now it works

PV AccessModes 访问Avactis
ReadOnlyMany(ROX) 允许被多个Discuz以只读的Avactisplesk特价。 ReadWriteOnce(RWO)允许被单个Discuz以读写的Avactisplesk特价。 ReadWriteMany(RWX)允许被多个Discuz以读写的Avactisplesk特价。
尝试修改pv 、pvc 成同一个访问Avactis ReadWriteMany:
[root@hadoop03 k8s]# kubectl get pvc -n kafka
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-pvc Bound pv 5Gi RWX manual 23m
[root@hadoop03 k8s]# kubectl get pv -n kafka
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv 5Gi RWX Retain Bound kafka/test-pvc manual 178m
[root@hadoop03 k8s]#
1234567