- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我想使用 Wickets @AuthorizationInstantiation
保护我的页面,并且应用程序应受 Spring Security Filter Chain
保护。
我在网上找到了一些示例,但没有一个与我想要实现该应用程序的方式相匹配。
我想在我的 Wicket 页面中使用类似 @AuthorizeInstantiation({"user", "admin"})
的内容,以及稍后使用其他 Wicket 特定方式来授权我的应用程序。
当我将应用程序部署到 Tomcat 并在浏览器中调用登录页面(或其他页面)时,会发生无休止的重定向。
我猜MySecurityConfigurerAdapter#configure(HttpSecurity http)
有问题
Wicket 不会调用我的 authenticate(username, password)
实现中的 getRoles()
和 AuthenticatedWebSession
方法。
下面是我的代码的摘录。完整的 MCVE 可在 Gitlab 上找到
WebSecurityConfigurerAdapter
的实现@Configuration
@EnableWebSecurity
public class MySecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws
Exception {
authenticationManagerBuilder.userDetailsService(new MyUserDetailsService());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//@formatter:off
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/logout_success").permitAll()
.antMatchers("login").permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.loginProcessingUrl("/login")
.and()
.addFilter(new SecurityContextPersistenceFilter()).securityContext();
//@formatter:on
}
@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
}
UserDetailsService
的实现public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Collection<MyAuthority> authorities = new HashSet<>();
MyAuthority admin = new MyAuthority("admin");
MyAuthority user = new MyAuthority("user");
MyAuthority guest = new MyAuthority("guest");
switch (username) {
case "tim":
case "steve":
authorities.add(admin);
authorities.add(user);
authorities.add(guest);
break;
case "craig":
authorities.add(user);
authorities.add(guest);
break;
case "phil":
authorities.add(guest);
break;
default:
throw new UsernameNotFoundException("user \"" + username + "\" unknown");
}
return new User(username, "123456", authorities);
}
class MyAuthority implements GrantedAuthority {
private final String role;
MyAuthority(String r) {
role = r;
}
@Override
public String getAuthority() {
return role;
}
}
}
AbstractSecurityWebApplicationInitializer
的实现public class MySecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer
{
public MySecurityWebApplicationInitializer()
{
super(MySecurityConfigurerAdapter.class);
}
@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext)
{
super.beforeSpringSecurityFilterChain(servletContext);
}
@Override
protected void afterSpringSecurityFilterChain(ServletContext servletContext)
{
super.afterSpringSecurityFilterChain(servletContext);
Filter myWicketFilter=new WicketFilter(new MyApplication())
{
@Override
public void init(boolean isServlet, FilterConfig filterConfig) throws ServletException
{
setFilterPath("");
super.init(isServlet, filterConfig);
}
};
FilterRegistration.Dynamic wicketRegistration;
wicketRegistration = servletContext.addFilter("myWicketFilter", myWicketFilter);
wicketRegistration.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "*");
}
}
public class MyApplication extends AuthenticatedWebApplication {
@Override
protected void init() {
super.init();
getComponentInstantiationListeners().add(new SpringComponentInjector(this));
getSecuritySettings().setAuthorizationStrategy(new AnnotationsRoleAuthorizationStrategy(this));
mountPage("/login", Login.class);
mountPage("/start", UserStart.class);
mountPage("/public", Public.class);
mountPage("/admin", Admin.class);
}
@Override
protected Class<? extends AbstractAuthenticatedWebSession> getWebSessionClass() {
return MyWebSession.class;
}
@Override
protected Class<? extends WebPage> getSignInPageClass() {
return Login.class;
}
@Override
public Class<? extends Page> getHomePage() {
return UserStart.class;
}
}
AuthenticatedWebSession
的实现public class MyWebSession extends AuthenticatedWebSession {
@SpringBean
private
AuthenticationManager authenticationManager;
public MyWebSession(Request request) {
super(request);
Injector.get().inject(this);
}
@Override
protected boolean authenticate(String username, String password) {
boolean authenticated;
try {
Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username
, password));
SecurityContextHolder.getContext().setAuthentication(authentication);
authenticated = authentication.isAuthenticated();
System.out.println("Authentication: "+authenticated+", User \""+username+"\"");
}
catch (AuthenticationException e) {
authenticated = false;
System.err.println("Login mit \"" + username + "\" fehlgeschlagen, " + e.getMessage());
}
return authenticated;
}
@Override
public Roles getRoles() {
Roles roles = new Roles();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.isAuthenticated()) {
for (GrantedAuthority authority : authentication.getAuthorities()) {
roles.add(authority.getAuthority());
}
}
System.out.println("Roles: "+roles.toString());
return roles;
}
}
我在 /
中插入了缺失的 .antMatchers("login").permitAll()
,但没有帮助。
当我调用 http://localhost:8080/context_name/login
时,我看到登录页面。提交表单后,它会出现 StackOverflowError
:
java.lang.StackOverflowError
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:163)
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494)
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494)
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494)
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494)
这是 Spring Security 调试日志的摘录:
********************************************************************
********** Security debugging is enabled. *************
********** This may include sensitive information. *************
********** Do not use in a production system! *************
********************************************************************
23-Jul-2018 16:42:40.561 INFO [RMI TCP Connection(3)-127.0.0.1] org.springframework.web.context.ContextLoader.initWebApplicationContext Root WebApplicationContext: initialization completed in 936 ms
[RMI TCP Connection(3)-127.0.0.1] INFO org.apache.wicket.Application - [myWicketFilter] init: Wicket core library initializer
[RMI TCP Connection(3)-127.0.0.1] INFO org.apache.wicket.Application - [myWicketFilter] init: Wicket extensions initializer
[RMI TCP Connection(3)-127.0.0.1] INFO org.apache.wicket.protocol.http.WebApplication - [myWicketFilter] Started Wicket version 8.0.0 in DEVELOPMENT mode
********************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode. ***
*** ^^^^^^^^^^^ ***
*** Do NOT deploy to your live server(s) without changing this. ***
*** See Application#getConfigurationType() for more information. ***
********************************************************************
[2018-07-23 04:42:40,779] Artifact wicketAuthSpringSec:war: Artifact is deployed successfully
[2018-07-23 04:42:40,779] Artifact wicketAuthSpringSec:war: Deploy took 3.465 milliseconds
23-Jul-2018 16:42:40.951 INFO [http-apr-8080-exec-4] Spring Security Debugger.info
************************************************************
Request received for GET '/':
org.apache.catalina.connector.RequestFacade@16ec26d8
servletPath:/
pathInfo:null
headers:
user-agent: IntelliJ IDEA/181.5281.24
accept-encoding: gzip
cache-control: no-cache
pragma: no-cache
host: localhost:8080
accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
connection: keep-alive
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
23-Jul-2018 16:42:41.013 INFO [http-apr-8080-exec-6] Spring Security Debugger.info
************************************************************
Request received for GET '/start':
org.apache.catalina.connector.RequestFacade@16ec26d8
servletPath:/start
pathInfo:null
headers:
user-agent: IntelliJ IDEA/181.5281.24
accept-encoding: gzip
cache-control: no-cache
pragma: no-cache
host: localhost:8080
accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
connection: keep-alive
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
Roles: ROLE_ANONYMOUS
23-Jul-2018 16:42:41.075 INFO [http-apr-8080-exec-6] Spring Security Debugger.info
************************************************************
New HTTP session created: 547244D1E42D71DA11F9BAD666EBFC3F
Call stack:
at org.springframework.security.web.debug.Logger.info(Logger.java:44)
at org.springframework.security.web.debug.DebugRequestWrapper.getSession(DebugFilter.java:166)
at org.springframework.security.web.debug.DebugRequestWrapper.getSession(DebugFilter.java:177)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:231)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:231)
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:231)
at org.apache.wicket.session.HttpSessionStore.getHttpSession(HttpSessionStore.java:85)
at org.apache.wicket.session.HttpSessionStore.getSessionId(HttpSessionStore.java:146)
at org.apache.wicket.Session.bind(Session.java:270)
at org.apache.wicket.RestartResponseAtInterceptPageException$InterceptData.set(RestartResponseAtInterceptPageException.java:140)
at org.apache.wicket.RestartResponseAtInterceptPageException.<init>(RestartResponseAtInterceptPageException.java:82)
at org.apache.wicket.RestartResponseAtInterceptPageException.<init>(RestartResponseAtInterceptPageException.java:68)
at org.apache.wicket.authroles.authentication.AuthenticatedWebApplication.restartResponseAtSignInPage(AuthenticatedWebApplication.java:103)
at org.apache.wicket.authroles.authentication.AuthenticatedWebApplication.onUnauthorizedInstantiation(AuthenticatedWebApplication.java:81)
at org.apache.wicket.Application$1.onInstantiation(Application.java:279)
at org.apache.wicket.application.ComponentInstantiationListenerCollection$1.notify(ComponentInstantiationListenerCollection.java:38)
at org.apache.wicket.application.ComponentInstantiationListenerCollection$1.notify(ComponentInstantiationListenerCollection.java:34)
at org.apache.wicket.util.listener.ListenerCollection.notify(ListenerCollection.java:80)
at org.apache.wicket.application.ComponentInstantiationListenerCollection.onInstantiation(ComponentInstantiationListenerCollection.java:33)
at org.apache.wicket.Component.<init>(Component.java:679)
at org.apache.wicket.MarkupContainer.<init>(MarkupContainer.java:178)
at org.apache.wicket.Page.<init>(Page.java:171)
at org.apache.wicket.Page.<init>(Page.java:135)
at org.apache.wicket.markup.html.WebPage.<init>(WebPage.java:74)
at de.example.app.pages.UserStart.<init>(UserStart.java:10)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:175)
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:67)
at org.apache.wicket.DefaultMapperContext.newPageInstance(DefaultMapperContext.java:90)
at org.apache.wicket.core.request.handler.PageProvider$Provision.getPage(PageProvider.java:380)
at org.apache.wicket.core.request.handler.PageProvider.getPageInstance(PageProvider.java:171)
at org.apache.wicket.request.handler.render.PageRenderer.getPage(PageRenderer.java:78)
at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:231)
at org.apache.wicket.core.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:202)
at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:912)
at org.apache.wicket.request.RequestHandlerExecutor.execute(RequestHandlerExecutor.java:65)
at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:283)
at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:253)
at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:221)
at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:262)
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:204)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:286)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:90)
at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:77)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2508)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2497)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
************************************************************
23-Jul-2018 16:42:41.091 INFO [http-apr-8080-exec-8] Spring Security Debugger.info
************************************************************
Request received for GET '/login':
org.apache.catalina.connector.RequestFacade@16ec26d8
servletPath:/login
pathInfo:null
headers:
user-agent: IntelliJ IDEA/181.5281.24
accept-encoding: gzip
cache-control: no-cache
pragma: no-cache
host: localhost:8080
accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
connection: keep-alive
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
23-Jul-2018 16:42:41.216 INFO [http-apr-8080-exec-8] Spring Security Debugger.info
************************************************************
New HTTP session created: 55EDC4A7C5B989B253923455CE54965A
最佳答案
当我发现StackOverflowError Trying to Expose AuthenticationManager in Spring WebSecurityConfigurerAdapter时我解决了核心问题.
无限循环是由重写 authenticationManager()
而不是 authenticationManagerBean()
引起的。 userDetailsServiceBean()
相同。
public class MySecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Autowired(name="userDetailsService")
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws
Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
....
}
@Bean(name="authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/* not working:
public AuthenticationManager authenticationManager() { ... }
*/
@Bean(name="userDetailsService")
@Override
public UserDetailsService userDetailsServiceBean() {
return new MyUserDetailsService();
}
// not working: UserDetailsService userDetailsService() { ... }
}
关于java - 使用 Spring Security 过滤器链、重定向循环进行 Wicket 授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51446718/
我正在尝试使用谷歌浏览器的 Trace Event Profiling Tool分析我正在运行的 Node.js 应用程序。选择点样本后,我可以在三种 View 之间进行选择: 自上而下(树) 自上而
对于一个可能是菜鸟的问题,我们深表歉意,但尽管在 SO 上研究了大量教程和其他问题,但仍找不到答案。 我想做的很简单:显示一个包含大量数据库存储字符串的 Android ListView。我所说的“很
我已经开始了一个新元素的工作,并决定给 Foundation 5 一个 bash,看看它是什么样的。在创建带有水平字段的表单时,我在文档中注意到的第一件事是它们使用大量 div 来设置样式。所以我在下
我有一个 Windows 窗体用户控件,其中包含一个使用 BeginInvoke 委托(delegate)调用从单独线程更新的第 3 方图像显示控件。 在繁重的 CPU 负载下,UI 会锁定。当我附加
我有一堆严重依赖dom元素的JS代码。我目前使用的测试解决方案依赖于 Selenium ,但 AFAIK 无法正确评估 js 错误(addScript 错误不会导致您的测试失败,而 getEval 会
我正在制作一款基于滚动 2D map /图 block 的游戏。每个图 block (存储为图 block [21][11] - 每个 map 总共 231 个图 block )最多可以包含 21 个
考虑到以下情况,我是前端初学者: 某个 HTML 页面应该包含一个沉重的图像(例如 - 动画 gif),但我不想强制客户缓慢地等待它完全下载才能享受一个漂亮的页面,而是我更愿意给他看一个轻量级图像(例
我正在设计一个小软件,其中包括: 在互联网上获取资源, 一些用户交互(资源的快速编辑), 一些处理。 我想使用许多资源(它们都列在列表中)来这样做。每个都独立于其他。由于编辑部分很累,我想让用户(可能
我想比较两个理论场景。为了问题的目的,我简化了案例。但基本上它是您典型的生产者消费者场景。 (我关注的是消费者)。 我有一个很大的Queue dataQueue我必须将其传输给多个客户端。 那么让我们
我有一个二元分类问题,标签 0 和 1(少数)存在巨大不平衡。由于测试集带有标签 1 的行太少,因此我将训练测试设置为至少 70-30 或 60-40,因此仍然有重要的观察结果。由于我没有过多地衡量准
我是一名优秀的程序员,十分优秀!