【发布时间】:2016-09-08 19:33:48
【问题描述】:
我知道这是 n。关于 Spring Security 的帖子,我确实阅读了很多关于它的内容,直到我决定发布我的问题,因为 - 我认为 - 由于 Spring Boot 的性质,引擎盖下一定隐藏着某种问题,这是特定于我正在使用的引导版本/安全类型的星座。
让我进入它。
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
我的基本安全配置:
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private StudentRepository studentRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/").access("hasRole('ROLE_STUDENT')")
.antMatchers("/**").permitAll();
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Iterable<Student> studentsWithIds = studentRepository.findAll();
for (Student student: studentsWithIds) {
if (student.getName() == username) {
return studentRepository.findOne(student.getId());
}
}
throw new UsernameNotFoundException("User '" + username + "' not found.");
}
});
}
}
我的学生类实现了 UserDetails(为简单起见,使用硬连线凭据。角色是 ROLE_STUDENT):
@Entity
public class Student implements UserDetails {
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
@Column(unique=true)
private Integer facebookId;
@Column(unique=true)
private Integer googleId;
private String name = "";
private String password = "";
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public String getPassword() {
return this.password;
}
public void initialize(String studentName) {
this.name = "student1";
this.password = "password";
}
@Override
public String toString(){
return "Student with name " + name + "id: " + id;
}
public Integer getId() {
return id;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_STUDENT"));
}
@Override
public String getUsername() {
return this.name;
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
}
就是这样。我没有任何其他与安全相关的配置或注释,据我所知,我不需要其他任何东西。
问题是,当我启动应用程序时,我仍然无法使用“student1”/“password”验证自己,而只能使用默认的“user”/。
知道缺少什么吗?谢谢!
Naturally there is a user already in the database 开启调试模式后:
22:06:54.067 [http-nio-8280-exec-1] 调试 o.s.s.w.a.AnonymousAuthenticationFilter - 使用匿名令牌填充 SecurityContextHolder:'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc:主体:anonymousUser;凭证:[受保护];已认证:真实;详细信息:org.springframework.security.web.authentication.WebAuthenticationDetails@b364:RemoteIpAddress:0:0:0:0:0:0:0:1;会话ID:空;授予权限:ROLE_ANONYMOUS' 22:06:54.067 [http-nio-8280-exec-1] 调试 org.springframework.security.web.FilterChainProxy - /students/1 在附加过滤器链中的第 11 位;触发过滤器:'SessionManagementFilter' 22:06:54.067 [http-nio-8280-exec-1] 调试 org.springframework.security.web.FilterChainProxy - /students/1 位于附加过滤器链中 11 的第 10 位;触发过滤器:'ExceptionTranslationFilter' 22:06:54.067 [http-nio-8280-exec-1] DEBUG org.springframework.security.web.FilterChainProxy - /students/1 在附加过滤器链中的第 11 位;触发过滤器:'FilterSecurityInterceptor' 22:06:54.068 [http-nio-8280-exec-1] 调试 o.s.s.w.access.intercept.FilterSecurityInterceptor - 安全对象:FilterInvocation:URL:/students/1;属性:[hasAnyRole('ROLE_USER')] 22:06:54.068 [http-nio-8280-exec-1] DEBUG o.s.s.w.access.intercept.FilterSecurityInterceptor - 先前经过身份验证:org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc:主体:anonymousUser;凭证:[受保护];已认证:真实;详细信息:org.springframework.security.web.authentication.WebAuthenticationDetails@b364:RemoteIpAddress:0:0:0:0:0:0:0:1;会话ID:空;授予权限:ROLE_ANONYMOUS 22:06:54.072 [http-nio-8280-exec-1] DEBUG o.s.security.access.vote.AffirmativeBased - 投票者:org.springframework.security.web.access.expression.WebExpressionVoter@272de199,返回:-1 22:06:54.072 [http-nio-8280-exec-1] 调试 o.s.b.factory.support.DefaultListableBeanFactory - 返回单例 bean 'delegatingApplicationListener' 的缓存实例 22:06:54.073 [http-nio-8280-exec-1] DEBUG o.s.security.web.access.ExceptionTranslationFilter - 访问被拒绝(用户是匿名的);重定向到身份验证入口点 org.springframework.security.access.AccessDeniedException:访问被拒绝 在 org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) 在 org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) 在 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) 在 org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) 在 org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 在 org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 在 org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 在 org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 在 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522) 在 org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095) 在 org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(未知来源) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(未知来源) 在 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 在 java.lang.Thread.run(未知来源) 22:06:54.073 [http-nio-8280-exec-1] 调试 o.s.security.web.access.ExceptionTranslationFilter - 调用身份验证入口点。 22:06:54.073 [http-nio-8280-exec-1] 调试 o.s.s.web.context.SecurityContextPersistenceFilter - SecurityContextHolder 现在已清除,因为请求处理已完成 22:06:54.073 [http-nio-8280-exec-1] 调试 o.s.boot.context.web.OrderedRequestContextFilter - 清除线程绑定请求上下文:org.apache.catalina.connector.RequestFacade@13a7abbc 22:06:54.077 [http-nio-8280-exec-1] 调试 org.springframework.web.servlet.DispatcherServlet - 名称为“dispatcherServlet”的 DispatcherServlet 处理 [/error] 的 GET 请求 22:06:54.080 [http-nio-8280-exec-1] 调试 o.s.w.s.m.m.a.RequestMappingHandlerMapping - 查找路径/错误的处理程序方法 22:06:54.083 [http-nio-8280-exec-1] 调试 oswsmmaRequestMappingHandlerMapping - 返回处理程序方法 [public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax. servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)] 22:06:54.083 [http-nio-8280-exec-1] 调试 o.s.b.factory.support.DefaultListableBeanFactory - 返回单例 bean 'basicErrorController' 的缓存实例 22:06:54.084 [http-nio-8280-exec-1] 调试 org.springframework.web.servlet.DispatcherServlet - [/error] 的上次修改值为:-1 22:06:54.084 [http-nio-8280-exec-1] 调试 o.s.o.j.support.OpenEntityManagerInViewInterceptor - 在 OpenEntityManagerInViewInterceptor 中打开 JPA EntityManager 22:06:54.104 [http-nio-8280-exec-1] 调试 oswservlet.view.ContentNegotiatingViewResolver - 请求的媒体类型是 [text/html, text/html;q=0.8] 基于 Accept 标头类型和可生产的媒体类型[文本/html]) 22:06:54.104 [http-nio-8280-exec-1] 调试 o.s.b.factory.support.DefaultListableBeanFactory - 返回单例 bean 的缓存实例“错误” 22:06:54.107 [http-nio-8280-exec-1] 调试 o.s.b.factory.support.DefaultListableBeanFactory - 在名为“错误”的 bean 上调用 afterPropertiesSet() 22:06:54.107 [http-nio-8280-exec-1] 调试 oswservlet.view.ContentNegotiatingViewResolver - 根据请求的媒体类型“text/”返回 [org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView@2fb1fefe] html' 22:06:54.107 [http-nio-8280-exec-1] 调试 org.springframework.web.servlet.DispatcherServlet - 在 DispatcherServlet 中使用名称渲染视图 [org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView@2fb1fefe] 'dispatcherServlet' 22:06:54.113 [http-nio-8280-exec-1] 调试 o.s.o.j.support.OpenEntityManagerInViewInterceptor - 在 OpenEntityManagerInViewInterceptor 中关闭 JPA EntityManager 22:06:54.113 [http-nio-8280-exec-1] 调试 o.s.orm.jpa.EntityManagerFactoryUtils - 关闭 JPA EntityManager 22:06:54.113 [http-nio-8280-exec-1] 调试 org.springframework.web.servlet.DispatcherServlet - 成功完成请求 22:06:54.114 [http-nio-8280-exec-1] 调试 o.s.b.factory.support.DefaultListableBeanFactory - 返回单例 bean 'delegatingApplicationListener' 的缓存实例 22:07:02.728 [http-nio-8280-exec-2] 调试 o.s.boot.context.web.OrderedRequestContextFilter - 将请求上下文绑定到线程:org.apache.catalina.connector.RequestFacade@13a7abbc 22:07:02.728 [http-nio-8280-exec-2] DEBUG o.s.s.web.util.matcher.AntPathRequestMatcher - 检查请求的匹配:'/students/1';反对'/css/' 22:07:02.728 [http-nio-8280-exec-2] DEBUG o.s.s.web.util.matcher.AntPathRequestMatcher - 检查请求的匹配:'/students/1';反对'/js/' 22:07:02.728 [http-nio-8280-exec-2] DEBUG o.s.s.web.util.matcher.AntPathRequestMatcher - 检查请求的匹配:'/students/1';反对 '/images/' 22:07:02.728 [http-nio-8280-exec-2] DEBUG o.s.s.web.util.matcher.AntPathRequestMatcher - 检查请求的匹配:'/students/1';反对'//favicon.ico' 22:07:02.728 [http-nio-8280-exec-2] DEBUG o.s.s.web.util.matcher.AntPathRequestMatcher - 检查请求的匹配:'/students/1';反对'/错误' 22:07:02.728 [http-nio-8280-exec-2] 调试 o.s.security.web.util.matcher.OrRequestMatcher - 尝试使用 Ant [pattern='/'] 进行匹配 22:07:02.728 [http-nio-8280-exec-2] 调试 o.s.s.web.util.matcher.AntPathRequestMatcher - 请求“/students/1”与通用模式“/”匹配 22:07:02.728 [http-nio-8280-exec-2] 调试 o.s.security.web.util.matcher.OrRequestMatcher - 匹配 22:07:02.728 [http-nio-8280-exec-2] 调试 org.springframework.security.web.FilterChainProxy - /students/1 在附加过滤器链中的第 11 位;触发过滤器:'WebAsyncManagerIntegrationFilter' 22:07:02.728 [http-nio-8280-exec-2] 调试 org.springframework.security.web.FilterChainProxy - /students/1 位于附加过滤器链中 11 的第 2 位;触发过滤器:'SecurityContextPersistenceFilter' 22:07:02.728 [http-nio-8280-exec-2] 调试 org.springframework.security.web.FilterChainProxy - /students/1 在附加过滤器链中的第 11 位;触发过滤器:'HeaderWriterFilter' 22:07:02.728 [http-nio-8280-exec-2] 调试 ossecurity.web.header.writers.HstsHeaderWriter - 不注入 HSTS 标头,因为它与 requestMatcher org.springframework.security.web.header.writers 不匹配.HstsHeaderWriter$SecureRequestMatcher@37ca7e0d 22:07:02.728 [http-nio-8280-exec-2] 调试 org.springframework.security.web.FilterChainProxy - /students/1 位于附加过滤器链中 11 的第 4 位;触发过滤器:'LogoutFilter' 22:07:02.728 [http-nio-8280-exec-2] DEBUG o.s.s.web.util.matcher.AntPathRequestMatcher - 检查请求的匹配:'/students/1';反对“/注销” 22:07:02.728 [http-nio-8280-exec-2] 调试 org.springframework.security.web.FilterChainProxy - /students/1 位于附加过滤器链中 11 的第 5 位;触发过滤器:'BasicAuthenticationFilter' 22:07:02.730 [http-nio-8280-exec-2] 调试 o.s.s.w.a.www.BasicAuthenticationFilter - 为用户“student1”找到基本身份验证授权标头 22:07:02.730 [http-nio-8280-exec-2] 调试 o.s.security.authentication.ProviderManager - 使用 org.springframework.security.authentication.dao.DaoAuthenticationProvider 进行身份验证尝试 22:07:02.731 [http-nio-8280-exec-2] 调试 o.s.s.authentication.dao.DaoAuthenticationProvider - 找不到用户“student1”
最后似乎是最有趣的,尽管其余部分也很丑:
o.s.s.authentication.dao.DaoAuthenticationProvider - 用户 'student1' 没找到
这是我在 Student 上调用初始化的地方(这是作弊,因为它应该在 POST 上调用,但同样,我作弊只是为了将 Student 放入数据库中,并将其用于身份验证。显然会有所不同稍后。当然,我只能在我暂时停用应用程序的安全性时进行此 GET):
@RequestMapping(value="/students", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<Iterable<Student>> listStudents() {
LOGGER.info("/students controller method call"+new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date()));
Iterable<Student> studentsFound = studentRepository.findAll();
Student newStudent = new Student();
newStudent.initialize("student1");
studentRepository.save(newStudent);
return new ResponseEntity<Iterable<Student>>(studentsFound, HttpStatus.OK);
}
您认为 Student 实例本身是否不正确?
【问题讨论】:
-
你在哪里调用了
Student的initialize方法? -
添加了初始化部分。扩展了一些解释(我知道它在那里没有意义,但只是想将一个学生保存到数据库中,无论在哪里。那部分已经在没有身份验证的情况下工作,所以我把它放在那里。数据库处于更新模式,记录当然还在数据库中,但我也仔细检查过)
标签: java spring spring-mvc spring-security spring-boot