跳转到内容
彼岸论坛

小天管理

管理员
  • 内容数

    15839
  • 注册日期

  • 最后上线

  • 得奖次数

    1

小天管理 发表的所有内容

  1. 提问前 遇到问题时,每个人心里都很着急。但是在决定在社区提问问题前,最好先做做以下功课: 尝试从官方文档中找到答案 确保自己至少读过一些官方文档。这样在遇到问题时,如果能回忆起只言片语,就可以再去读一遍相关文档,问题往往也就解决了。 Google 是你的朋友 对于成熟的开源项目,你遇到的问题,很可能别人也遇到过。这时通过 Google、百度 等网站的搜索服务,可以帮你快速定位并解决问题。永远记住,地球上的你并不孤单,包括你遇到的问题。 挖掘 Bug 宝藏 开源软件一般都会有自己的 Bug 管理方案,提问之前先通过搜索看看有无你遇到的问题。一个运作良好的 Bug 库,经常是一座巨大的宝藏。对于活跃社区来说,这一招经常很管用。 求助身边的朋友 如果你使用的开源软件,在朋友圈或同事圈里也有人使用,那么抬起你的脚、或拿起你的电话,真挚诚恳的探讨不会遭遇拒绝,而会增进友谊。不要犹豫,你的内心渴望面对面交流,你的朋友也是。 如果以上 4 步都无法解决你遇到的问题,也别犹豫,立马向彼岸论坛提交问题就好。 提问时 平和对等的心态 提问时,不要把自己摆在顾客的位置,比如 另外,也不要把自己摆在乞食者的位置,比如 在彼岸论坛,一切皆是朋友。你和他们都是对等的。你的提问是在帮助论坛的完善。平和对等的心态,可以让你的问题赢得更多人的阅读和思考。 通过论坛而不是Telegram/IRC群组来提问 我们不推荐你在 Telegram群、IRC频道等这些地方提问(但这不是强制的),因为这些交流方式是即时的,所以它的缺点也显而易见:你很难对这个问题及其解答做总结和归档。 而在论坛提问可以很好的实现这个功能,这样当另一个人发现了一个相同的问题时,他可以很容易的通过搜索论坛里以前的帖子来找到解决方案,避免重复劳动。 使用明确、有意义的标题 抱着平和对等的心态,找到合适的途径后,就得静下心来将遇到的问题写成文字。书写文字不是一件简单的事情,我们可以从遵循一些简单的规则开始。 首先是标题要简洁清晰,要言之有物。比如 上面的标题很糟糕,光看标题作者无法知道发生了什么事。当彼岸论坛的问题很多时,上面这类标题,经常会让作者直接忽视或将优先级降到很低。 明确、有意义的标题,可以帮助作者确定问题具体是什么类型、预估需要多少时间解决、是否现在马上解决等。一个好的标题,也有利于社区知识的沉淀和后期搜索。标题有如一个人的颜面衣着,虽然不是关键,但在嘈杂的信息社区中,这很重要。 语法正确、格式清晰 虽然我们不是作家,但正确的语法、清晰的格式,可以让读者赏心悦目,也就更有心情帮你一起思考解决问题。 对于很多需要代码来描述的问题,要尤其注意格式,这能让你的内容看起来很专业,社区也就更有意愿会去帮助你,否则糟糕的排版,经常带来的是发帖之后的石沉大海。 描述事实、而不是猜测 事实是指,依次进行了哪些操作、产生了怎样的结果。而不要自己胡乱猜测, 有时不合理的猜测会让回答者一头雾水。因此,尽量避免猜测性描述,除非你能先描述事实,在事实描述清楚之后,再给出合理的猜测是欢迎的。 贴出你的错误日志或者硬件信息 一个功能完善的软件,必然会具备记录日志的功能。因此在出现问题时,最好尽可能详尽地贴出相应的错误日志,这样可以帮助回答者更好地理解错误发生时的情景,也就能更好的给出解决方案。 另外,如果你的问题是与硬件或者驱动相关的,最好在问题描述中给出你的机器的详细硬件配置。这也对诊断问题非常有用。 仔细检查、确保准确 是人都会犯错误,特别是在如此快节奏的互联网环境下。好不容易把问题描述清楚时,不要急着立刻提交。在提交前,至少保证从头到尾再仔细阅读一遍,比如语法错误、错别字、标点符号、排版等等。做到这些,不光是尊重别人,也是尊重自己。 提问后 等待回复 互联网上最有效的沟通方式是异步沟通。因此,提交问题之后,不要期待有人会马上给予回复,也不要心烦意乱着急地等待,更不要因为帖子暂时没有人回复而重复发贴或顶贴。可以先去忙点儿别的事情,如果有人回复,论坛会有邮件提示你的。 及时补充信息 在接收到回复时,仔细阅读。最经常的情况是,社区回复的,经常不是你想要的答案。比如 ‘‘根据你的描述,问题无法重现。能否提供具体使用环境和重现步骤?’’ 这时要淡定。仔细看看自己提交的问题描述是否足够清晰,如果有可补充的信息,尽量补充,以帮助作者能尽快定位问题。 要记得,谦和淡定的交流,不光能帮助你解决问题,还有助于你结交更多朋友。 适当的总结 当问题终于解决时,建议对问题进行总结。可以直接编辑原帖进行总结。你的总结,会让遇到同样问题的朋友们受益,并且对自己的技能也是一种提高。无论国内还是国外,有很多牛人之所以成为牛人,很大程度上都是因为有总结思考的好习惯。 不要忘记感谢 事实上,没有人有义务帮你解决问题,要知道,每个人的时间都很宝贵,所以,应该衷心感谢那些在社区中帮助过你的人。 同时,也希望你能在力所能及的事情多多帮助一下其他的提问者。唯有这样,社区才能在互助友爱的气氛中向前发展。 问题结束后不要隐藏或删除 我的论坛是一个公开的论坛,好的问题与好的答案相辅相成,后边的人看到同样的问题不会重复的去解决,问题解答人也是自发的去解决问题,目的都是为了为后人发光发热
  2. 下个版本我们要做前端插件化改造,最近在做技术调研。 大致需求: 前端画布项目,画布左侧有组件库,组件库中的组件可以拖拽到画布进行编排,每个组件有一个参数设置面板。 下个版本,每个组件做成一个插件(当然,有些组件是内置的,无需做成插件),组件插件输出 zip 包,可以上传、安装和卸载插件,主应用动态加载插件。有什么成熟的解决方案吗?
  3. 比如说在视频剪辑的性能上,MacBook Air M3 可以流畅回放的工程,自己配台式机的话,需要什么级别的处理器和显卡?
  4. 个人博客地址: https://penghh.fun RSS 订阅链接: https://penghh.fun/atom.xml
  5. 家里的开点民宿的小买卖,刚上架美团,来了单客人求人家帮忙写了个好评 结果美团发通知判定为刷单行为,订单数据不作数了 然后上小红书搜了下,说是因为好评发送得时候地点要在酒店附近?或者客户的行动轨迹要在当地 这我就纳闷了,那像我这样 位置权限都不放开给 app 的,或者说旅行期间没打开过美团的,岂不是都算刷单,有没哥们儿能帮我分析分析的。
  6. 前言 最近写了一个小程序, 后端用 springboot 搭建的单体, 鉴权就是使用的springboot + security 因为实现方式和网上检索的教程有些差异, 所以想请教一下, 接入 security 的正确打开方式是什么 正文 我会先讲解一下我的实现思路, 实现方法, 设计思路, 思路来源等等 然后举例说明网络检索的实现方式和差异 接着倒出我的疑惑, 不吝赐教, 烦请指正 项目结构 ├── security │ ├── config │ │ └── WebSecurityConfiguration.java │ ├── filter │ │ ├── GlobalBearerAuthenticationConverter.java │ │ └── GlobalBearerTokenAuthenticationFilter.java │ ├── handler │ │ ├── GlobalAccessDeniedHandler.java │ │ ├── GlobalAuthenticationEntryPoint.java │ │ ├── GlobalAuthenticationFailureHandler.java │ │ └── GlobalAuthenticationSuccessHandler.java │ ├── holder │ │ └── UserHolder.java │ ├── impl │ │ ├── GlobalAuthenticationFilter.java │ │ ├── GlobalAuthenticationProvider.java │ │ ├── GlobalAuthenticationToken.java │ │ ├── phone │ │ │ ├── program │ │ │ │ └── mini │ │ │ │ └── wechat │ │ │ │ ├── WeChatMiniProgramAuthenticationFilter.java │ │ │ │ ├── WeChatMiniProgramAuthenticationProvider.java │ │ │ │ └── WeChatMiniProgramAuthenticationToken.java │ │ │ └── sms │ │ │ ├── PhoneSmsAuthenticationFilter.java │ │ │ ├── PhoneSmsAuthenticationProvider.java │ │ │ └── PhoneSmsAuthenticationToken.java │ │ └── refresh │ │ ├── RefreshAuthenticationFilter.java │ │ ├── RefreshAuthenticationProvider.java │ │ └── RefreshAuthenticationToken.java │ ├── properties │ │ ├── JwtProperties.java │ │ └── WebSecurityProperties.java │ ├── service │ │ ├── GlobalUserDetailsChecker.java │ │ ├── GlobalUserDetailsService.java │ │ └── UserInitService.java │ └── source │ ├── GlobalWebAuthenticationDetails.java │ └── GlobalWebAuthenticationDetailsSource.java 思路讲解 阅读源码 UsernamePasswordAuthenticationFilter public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username"; public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password"; private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/login", "POST"); private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY; private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY; private boolean postOnly = true; public UsernamePasswordAuthenticationFilter() { super(DEFAULT_ANT_PATH_REQUEST_MATCHER); } public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) { super(DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (this.postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); username = (username != null) ? username : ""; username = username.trim(); String password = obtainPassword(request); password = (password != null) ? password : ""; UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } 这是 Spring Security 中非常关键的一个基类, 等同于 Spring 框架原生态的给了你一个实现模板, 以常见的 username/password 的形式, 实现了基本的鉴权入口 private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/login","POST"); 这行代码决定了这个 Filter 只用来处理 Http 接口路径 为 /login 的请求 解析参数 String username = obtainUsername(request); username = (username != null) ? username : ""; username = username.trim(); String password = obtainPassword(request); password = (password != null) ? password : ""; 本质就是读取 Query 参数, 没有非常深入的东西 构建 Authentication UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); UsernamePasswordAuthenticationToken 这个类是比较重要 Authentication 类, 基本就相当于持有鉴权 未认证前, 存储 username/password/detail 认证后, 存储服务端发放的认证信息, 比如 Token?Cookie?Session?Or Other? 构建 Detail setDetails(request, authRequest); 这个 details 本质上也是 Authentication 中比较重要的东西, 可以用来解析和存储鉴权相关的数据, 比如请求头解析, UA/IP/Token/SessionId/Cookies 等等, 具体看想怎么用 鉴权验证 return this.getAuthenticationManager().authenticate(authRequest); getAuthenticationManager().authenticate()这是一段非常关键的代码, 因为此刻会进入 Security 除了 Filter 以外, 另外一个非常重要的概念, Provider, 也就是 AuthenticationProvider public interface AuthenticationProvider { Authentication authenticate(Authentication authentication) throws AuthenticationException; boolean supports(Class<?> authentication); } 他的作用就是接收未认证前的 Authentication, 进行解析,验证等操作, 然后返回认证后的 Authentication 同时 supports(Class<?> authentication)函数则是为了区分不同的 Authentication 寻找思路 基于以上源码可知, Security 最基本的几个单元已经找到了 Filter Authentication Provider 请求进入 Web 容器, 经由过滤器, 当 Filter 判断请求路径为登录请求, 则根据参数生成未认证 Authentication, 然后将未认证 Authentication 交由 Provider 进行认证, 并返回认证后的 Authentication Filter 可以制定请求路径, 可以处理一个或者多个请求路径 Authentication 可以制定存储单元, 不同的登陆方式存储单元不同 Provider 可以进行认证, 可以根据不同的 Authentication 来处理 基于以上结论, 那么我的基本思路是不是就可以有了 于是乎, 就有了以下设计方案 设计思路 public abstract class GlobalAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private final HttpMethod method; public GlobalAuthenticationFilter(String pattern, HttpMethod method) { super(new AntPathRequestMatcher(pattern, method.name()), SpringUtil.getBean(AuthenticationManager.class)); this.method = method; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (!method.matches(request.getMethod())) { throw new AuthenticationServiceException("登陆请求协议不支持"); } GlobalAuthenticationToken authentication = combinationAuthentication(request); return getAuthenticationManager().authenticate(authentication); } public abstract GlobalAuthenticationToken combinationAuthentication(HttpServletRequest request) throws IOException; 我先定义一个全局抽象 Filter 基类 GlobalAuthenticationFilter, 将必要的 Filter 实现流程定义好 然后将请求路径和协议, 通过构造函数的形式, 限制子实现的基本构造 定义一个 combinationAuthentication 函数, 将参数的解析和无认证的 Authentication 生成交由子实现 public class GlobalAuthenticationToken extends AbstractAuthenticationToken { private final Object principal; private final Object credentials; public GlobalAuthenticationToken(Object principal) { this(principal, null); } public GlobalAuthenticationToken(Object principal, Object credentials) { this(principal, credentials, null); } public GlobalAuthenticationToken(Object principal, Object credentials, Object details) { super(AuthorityUtils.NO_AUTHORITIES); this.principal = principal; this.credentials = credentials; setDetails(details); } public GlobalAuthenticationToken( Object principal, Object credentials, Object details, Collection<? extends GrantedAuthority> authorities ) { super(authorities); this.principal = principal; this.credentials = credentials; setDetails(details); setAuthenticated(true); } public static GlobalAuthenticationToken unauthenticated(Object principal) { return new GlobalAuthenticationToken(principal); } public static GlobalAuthenticationToken unauthenticated(Object principal, Object credentials) { return new GlobalAuthenticationToken(principal, credentials); } public static GlobalAuthenticationToken unauthenticated(Object principal, Object credentials, Object details) { return new GlobalAuthenticationToken(principal, credentials, details); } public static GlobalAuthenticationToken authenticated(Object principal) { return new GlobalAuthenticationToken(principal, null, null, AuthorityUtils.NO_AUTHORITIES); } public static GlobalAuthenticationToken authenticated(Object principal, Object credentials) { return new GlobalAuthenticationToken(principal, credentials, null, AuthorityUtils.NO_AUTHORITIES); } public static GlobalAuthenticationToken authenticated(Object principal, Object credentials, Object details) { return new GlobalAuthenticationToken(principal, credentials, details, AuthorityUtils.NO_AUTHORITIES); } @Override public Object getCredentials() { return credentials; } @Override public Object getPrincipal() { return principal; } } 我先定义一个全局 Authentication 基类 GlobalAuthenticationToken, 包含基本的 principal/credentials 以及源于 AbstractAuthenticationToken 的 detail 和 authorities 因为某些鉴权场景的特殊性, 我将构造函数尽可能全面的限制, 以防子实现出现缺漏, 并提供了足够的静态函数来支撑, 简化构造流程 @SuppressWarnings("unchecked") public abstract class GlobalAuthenticationProvider<AuthenticationToken extends Authentication> implements AuthenticationProvider { private final Class<AuthenticationToken> clazz; @Resource private UserDetailsService userDetailsService; @Resource private UserDetailsChecker userDetailsChecker; { Type superClass = getClass().getGenericSuperclass(); if (superClass instanceof ParameterizedType) { this.clazz = (Class<AuthenticationToken>) ((ParameterizedType) superClass).getActualTypeArguments()[0]; } else { throw new IllegalArgumentException("泛型类型未找到"); } } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = validate4Username((AuthenticationToken) authentication); UserDetails userDetails = userDetailsService.loadUserByUsername(username); userDetailsChecker.check(userDetails); GlobalAuthenticationToken token = GlobalAuthenticationToken.authenticated(userDetails, null, authentication.getDetails()); token.setDetails(authentication.getDetails()); return token; } public abstract String validate4Username(AuthenticationToken authentication); @Override public boolean supports(Class<?> authentication) { return clazz.isAssignableFrom(authentication); } } 我先定义一个全局抽象 Provider 基类 GlobalAuthenticationProvider, 并严格按照 Provider 的核心思路进行固有实现 通过泛型参数将 supports(Class<?> authentication)默认处理 定义抽象函数 abstract String validate4Username(AuthenticationToken authentication) 交由子类进行认证逻辑 其中有涉及到两个重点实现 @Resource private UserDetailsService userDetailsService; @Resource private UserDetailsChecker userDetailsChecker; public interface UserDetailsService { UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; } public interface UserDetailsChecker { void check(UserDetails toCheck); } 同样也是 Security 中较为核心的接口定义 其中 UserDetailsService 提供了开放实现接口 loadUserByUsername UserDetailsChecker 提供了 check 前者用来获取相关用户信息 后者用来校验相关用户信息 比如我的默认实现 @Slf4j @Service @RequiredArgsConstructor public class GlobalUserDetailsService implements UserDetailsService { private final UserService userService; @Override public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException { try { return Optional.ofNullable(userService.getByPhoneIncludeDelete(phone)) .orElseGet(() -> userService.newUser(phone)); } catch (Exception e) { log.error("加载用户失败={}", e.getMessage(), e); throw new UsernameNotFoundException("手机号异常", e); } } } @Component public class GlobalUserDetailsChecker implements UserDetailsChecker { @Override public void check(UserDetails user) { Assert.isTrue(user.isAccountNonLocked(), () -> new LockedException("账户已锁定")); Assert.isTrue(user.isEnabled(), () -> new DisabledException("账户已禁用")); Assert.isTrue(user.isAccountNonExpired(), () -> new AccountExpiredException("账户已过期")); Assert.isTrue(user.isCredentialsNonExpired(), () -> new CredentialsExpiredException("账户认证已过期")); } } 以上只是一个很简略的认证实现 具体实现 如我在[项目结构] 中展示的 我分别基于以上抽象, 实现了, 手机号/短信验证码 鉴权认证逻辑 @Component public class PhoneSmsAuthenticationFilter extends GlobalAuthenticationFilter { public static final String SPRING_SECURITY_FORM_PHONE_KEY = "phone"; public static final String SPRING_SECURITY_FORM_SMS_CODE_KEY = "smsCode"; public static final String SPRING_SECURITY_FROM_URI_PATTEN = "/**/user/login/phone"; public static final HttpMethod SPRING_SECURITY_FROM_METHOD = HttpMethod.GET; public PhoneSmsAuthenticationFilter() { super(SPRING_SECURITY_FROM_URI_PATTEN, SPRING_SECURITY_FROM_METHOD); } @Override public GlobalAuthenticationToken combinationAuthentication(HttpServletRequest request) { String phone = StrUtil.nullToEmpty( StrUtil.cleanBlank(request.getParameter(SPRING_SECURITY_FORM_PHONE_KEY))); String smsCode = StrUtil.nullToEmpty( StrUtil.cleanBlank(request.getParameter(SPRING_SECURITY_FORM_SMS_CODE_KEY))); GlobalWebAuthenticationDetails details = (GlobalWebAuthenticationDetails) authenticationDetailsSource.buildDetails( request); details .setClientType(ClientType.WeChatMiniProgram) .setLoginType(LoginType.PhoneSms); return new PhoneSmsAuthenticationToken(phone, smsCode, details); } } @Getter public class PhoneSmsAuthenticationToken extends GlobalAuthenticationToken { private final String phone; private final String smsCode; public PhoneSmsAuthenticationToken(String phone, String smsCode, Object details) { super(phone, smsCode, details); this.phone = phone; this.smsCode = smsCode; } } @Component @RequiredArgsConstructor public class PhoneSmsAuthenticationProvider extends GlobalAuthenticationProvider<PhoneSmsAuthenticationToken> { private final SmsService smsService; @Override public String validate4Username(PhoneSmsAuthenticationToken authentication) { String phone = authentication.getPhone(); String smsCode = authentication.getSmsCode(); String ip = ((GlobalWebAuthenticationDetails) authentication.getDetails()).getIp(); smsService.verifySmsCode(phone, ip, smsCode); return phone; } } 实现了, 微信小程序手机号快速验证 鉴权认证逻辑 @Component public class WeChatMiniProgramAuthenticationFilter extends GlobalAuthenticationFilter { public static final String SPRING_SECURITY_FORM_APP_ID_KEY = "appId"; public static final String SPRING_SECURITY_FORM_PHONE_CODE_KEY = "phoneCode"; public static final String SPRING_SECURITY_FROM_URI_PATTEN = "/user/login/wechat/miniapp"; public static final HttpMethod SPRING_SECURITY_FROM_METHOD = HttpMethod.POST; public WeChatMiniProgramAuthenticationFilter() { super(SPRING_SECURITY_FROM_URI_PATTEN, SPRING_SECURITY_FROM_METHOD); } @Override public GlobalAuthenticationToken combinationAuthentication(HttpServletRequest request) throws IOException { JSONObject paramJson = JSONUtil.parseObj(IoUtil.read(request.getInputStream(), StandardCharsets.UTF_8)); String appId = paramJson.getStr(SPRING_SECURITY_FORM_APP_ID_KEY); String phoneCode = paramJson.getStr(SPRING_SECURITY_FORM_PHONE_CODE_KEY); GlobalWebAuthenticationDetails details = (GlobalWebAuthenticationDetails) authenticationDetailsSource.buildDetails( request); details .setClientType(ClientType.WeChatMiniProgram) .setLoginType(LoginType.WeChatMiniProgram); return new WeChatMiniProgramAuthenticationToken(appId, phoneCode, details); } } @Getter public class WeChatMiniProgramAuthenticationToken extends GlobalAuthenticationToken { private final String appId; private final String phoneCode; public WeChatMiniProgramAuthenticationToken(String appId, String phoneCode, Object details) { super(appId, phoneCode, details); this.appId = appId; this.phoneCode = phoneCode; } } @Component @RequiredArgsConstructor public class WeChatMiniProgramAuthenticationProvider extends GlobalAuthenticationProvider<WeChatMiniProgramAuthenticationToken> { private final WxMiniAppService wxMiniAppService; @Override public String validate4Username(WeChatMiniProgramAuthenticationToken authentication) { if (ApplicationTools.isNotProd()) { throw new BadCredentialsException("当前环境不支持该登录方式!"); } String appId = authentication.getAppId(); String phoneCode = authentication.getPhoneCode(); if (!wxMiniAppService.switchover(appId)) { throw new BadCredentialsException(StrUtil.format("未找到对应微信小城 AppId=[{}]配置,请核实后重试", appId)); } WxMaPhoneNumberInfo phoneNoInfo; try { phoneNoInfo = wxMiniAppService .getUserService() .getPhoneNoInfo(phoneCode); } catch (WxErrorException e) { throw new BadCredentialsException(e .getError() .getErrorMsg()); } return phoneNoInfo.getPurePhoneNumber(); } } 实现了, 通过 refreshToken 刷新 Token 鉴权认证逻辑 篇幅有限, 这里就不继续贴代码了 基于此, 甚至还可以实现各类情况的鉴权认证过程, 不局限以上 Oauth2 的认证流程实现肯定是不一样的, 暂时不在此进行讨论 网络检索 类似直接写一个 Controller, 以常规化的 controller->service->dao(mapper)的方式, 比比皆是 当然也同样检索到类似我上述实现方式的文章, 只是大同小异 疑惑 以上是 Security 的正确打开方式? 还有其他实现思路和方案吗? 我自己的实现方式, 始终给我一种不够优雅, 不够简洁, 甚至于不方便定位的感觉 所以我想请教佬们关于这一点的看法
  7. Infuse 一年 18 优惠,非常适合小雅 emby 媒体库,apple tv 用户强烈推荐 优惠地址地址: https://firecore.cn/promo 小雅影视媒体库全家桶 永久免费的小雅 EMBY 媒体库全家桶搭建教程 https://xiaoyahost.pro/meitiku/xiaoyaemby/ tvOS 「 AppleTV 」上使用 小雅 xiaoya 媒体库 EMBY https://xiaoyahost.pro/appletv/emby/
  8. 目前的设备是 Mac mini 16 + 256G 版本,但是使用了一年多发现现在不够用了。 目前使用 Flutter 开发 ios 和 android 的软件。同时在开发软件的同时需要打开 Xcode 调试,并且还需要打开 Idea 跑一个 Springboot 的后端服务+一个后台管理的页面。 其他就是一些常见的软件,比如微信、QQ 什么的聊天软件,通常需要挂到后台。 需求:目前想使用 Macbook ,不想使用 mac mini 了,不知道各位有什么好的建议,预算大概在 10000 左右。 大家有什么好的建议没呢
  9. I wanted to share some job opportunities at TikTok. we are TikTok Global E-commerce Customer Business team. Our product engineering team is responsible for building an e-commerce ecosystem that is innovative, secure and intuitive for our users. We're currently hiring for mobile engineers at all levels in Seattle. We look forward to having you on board! Jobs details: - Tech Lead - Android Software Engineer: https://careers.tiktok.com/s/i6B6m5Sb - Tech Lead - IOS Software Engineer: https://careers.tiktok.com/s/i6B6XXSo - Senior Android Software Engineer: https://careers.tiktok.com/s/i6B67hUu - Senior iOS Software Engineer: https://careers.tiktok.com/s/i6BMLHLv - Software Engineer: https://careers.tiktok.com/s/i6BMeBPB 我们这边主要是 TT 电商,大前端基础架构的,会负责整个 TT 电商在大前端方向的性能优化和基建的工作,目前主要的 HC 在西雅图,合适的朋友欢迎加入~
  10. 由于没有美区 Paypal ,一直都是用礼品卡充值。不知道 iCloud+能不能余额来开通?
  11. 从来没用过这个 app,但是天天打骚扰电话
  12. 游戏行业卷了很多年 Unity 游戏开发者 主导设计过很多个游戏常用的框架,系统 上线的游戏产品有几个千万级别的 年龄 30+ 问题 主要使用的语言是 C#; 用过:JavaScript,TypeScript ,Objective-C ,C ,等等 (当然用过仅仅是因为项目中有一些需要源生功能需要) 目前厌倦了游戏行业,想转别的行业,但是一时又不知道向着哪个方向转 Reddit 上看了几篇同样想从 unity 转的,都是 .net 方向的 想听听 V 友的建议 谢谢
  13. 细化一下需求: AI 生产力:跑跑 SD ,跑跑 LLM ( 70B ?) 游戏娱乐:Stream 游戏(艾尔登法环) 预算范围:15000 (不含显示器、鼠键)
  14. 公司在香港,岗位是纯技术,公司主营发币,工资发 usdt ,这样的岗位有米有法律风险。 有了解的大佬愿意聊聊么。
  15. 看了些信息,都说 WiFi 信号不好,另外就是品控看脸。 不玩游戏,纯家用和轻办公,买这个是否合适? 另外,自己单买内存硬盘(如机器同品牌型号的)是否比直接带的价格更有性价比,还是买配好的?
  16. 前几天跟装维聊天 装维说上海电信现在大流量用户拨号会分到 116.网段。 主要是针对 PCDN 用户,说 116 网段会跑不起来。 我看了一下,我家和我同事家都在 116 网段了,我 pt 用户,暂时没发现啥影响,连接性什么的。
  17. 试驾宋 L ,动力啥的都满意,就是过坎的时候后排有点颠簸 试驾 N7 ,感觉的确质感上提升了很多,后排都是电动调节加按摩,屏幕多了很多,音响也好了不少。但是后排车窗有点小,贵了 2 万,和宋 L 顶配比没有智驾和四驱
  18. 远程岗位 远程岗位 远程岗位 职责 负责澳洲生活缴费平台的开发、接口对接。 所需技能和经验: 熟悉各种支付通道对接(支付宝、微信、各种信用卡、paypal 等) 熟悉支付流程 熟悉 laravel 框架,并使用 laravel 框架开发非前后端分离项目与前后端分离项目的经验 工作时间: 大小周 10:00-19:00 午休两小时 薪资区间: 8-13K 联系方式: Email: ansonyims@gmail.com
  19. ?si=XQJR8uwgAcbqASeG 无论怎么说,只有用过一段时间才能知道这是正经的优化手段还是纯整活的操作 很显然软盘已经退出历史舞台,但是 Windows 的盘符仍然从 C 开始。所以我就想,既然 Windows 的引导方式已经不依赖软盘,那能不能让 Windows 的盘符改成别的?于是就找到了这个视频。 这位老哥是在虚拟机上弄的,我在物理机上复现了一遍,把 Windows 盘符改成了 A 。目前没发现什么严重的错误提示,可以正常添加用户和对应的权限;如果电脑里没别的主分区,虚拟内存和休眠功能是默认禁用的,如果有第二个主分区,系统会给这个分区分配成 C 盘,页面文件和休眠文件就放在这里;绝大部分 UWP 应用能正常运行,appx 文件也可以正常安装,但我发现我其中一个 OEM 驱动安装程序运行不了; Windows Update 也能正常更新。 作者说过了,永远不要把除 C 以外的字母用作系统盘,因为有些应用只认 C 盘。所以我想知道,把系统盘符改了之后还适合日常乃至长期使用么?这也许能防御大多数病毒和流氓软件?
  20. Anki 卡组详见: https://v2ex.com/t/1015472 新建了一个 Anki 日语学习交流群,主要讨论(基于 Anki 的)日语学习、日本留学工作生活等和日本相关的内容。欢迎大家加群闲聊。 群链接: https://t.me/ankijapan ,或在 Telegram 中直接搜索 AnkiJapan 加入。
  21. 之前开土区全家桶大概 500RMB 一年,现在涨到 4k 多实在吃不消。听人说阿根廷便宜,但是现在风控很严,容易被 ban 是真的吗? ip 和信用卡的问题都能解决,求大佬指点
  22. 黄金一号都要 110 120 了,以前 75.。。我还嫌弃不喜欢买
  23. 一个小团队整出来的,https://www.zijizhang.com/u/qianduanren 一个简化独立开发者和个体户记账麻烦的 app, 确实牛逼,之前找人代记账,每年基本最少 1000+,现在自己可以在手机上记账报税了,一年 200 多就搞定了,推荐给各位大佬,喜欢的点赞,独立开发者不容易
  24. 没有其他别得爱好,就喜欢玩玩游戏。 现在年纪大了,时间少了,对任何游戏都提不起兴趣了。 只有空余时间和朋友打打瓦。 你们还在坚持什么游戏?
  25. rt ,想入手一个全新的,官网已经没了
×
×
  • 创建新的...