我一直在关注此示例,以便在我的网站上创建登录功能:
https://www.youtube.com/watch?v=XO-OdIXNU_o
但是我的登录尝试失败了。从堆栈跟踪中,找到一个用户名为“test”的用户,但是凭据出现错误(我已经尝试过使用和不使用加密的密码并且出现了相同的错误。
这是我的WebSecurityConfig.java文件:
package com.sitename.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.slf4j.*;
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = CustomUserDetailsService.class)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserDetailsService userDetailsService;
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/users/logout").authenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/users/login")
.usernameParameter("username").passwordParameter("password")
.defaultSuccessUrl("/")
.successHandler(successHandler())
//.failureHandler(failureHandler())
.permitAll();
}
@Bean
public AuthenticationSuccessHandler successHandler() {
log.info("Login success!");
SimpleUrlAuthenticationSuccessHandler handler = new SimpleUrlAuthenticationSuccessHandler();
handler.setUseReferer(true);
return handler;
}
// @Bean
// public AuthenticationFailureHandler failureHandler() {
// log.info("Login failure - bad credentials");
// return failureHandler();
// }
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
log.info("Running configureGlobal method in WebSecurityConfig");
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
// auth
// .inMemoryAuthentication()
// .withUser("user").password("password").roles("USER");
}
@Bean(name="passwordEncoder")
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
这是我的用户实体:
package com.sitename.domain.models;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;
@Entity
@Table(name = "users")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@NotBlank
@NotEmpty
@NotNull
@Column(name = "username")
private String username;
@NotBlank
@NotEmpty
@NotNull
@Column(name = "email")
private String email;
@NotBlank
@NotEmpty
@NotNull
@Column(name = "password")
private String password;
@NotBlank
@NotEmpty
@NotNull
@Column(name = "enabled")
private int enabled;
public User(String username, String password, String email, int enabled) {
this.username = username;
this.password = password;
this.email = email;
this.enabled = enabled;
}
public User(User user) {
this.id = user.id;
this.username = user.username;
this.email = user.email;
this.password = user.password;
this.enabled = user.enabled;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getEnabled() {
return enabled;
}
public void setEnabled(int enabled) {
this.enabled = enabled;
}
public User() {}
}
我的UserRole实体:
package com.sitename.domain.models;
import javax.persistence.*;
@Entity
@Table(name = "user_roles")
public class UserRole {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "role")
private String role;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
我的UserRepository:
package com.sitename.domain.repositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.sitename.domain.models.User;
@Repository
public interface UserRepository extends CrudRepository<User, Long> {
public User findByUsername(String username);
}
我的UserRoleRepository:
package com.sitename.domain.repositories;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.sitename.domain.models.UserRole;
import java.util.List;
@Repository
public interface UserRoleRepository extends CrudRepository<UserRole, Long> {
@Query("select a.role from UserRole a, User b where b.username=?1 and a.id=b.id")
public List<String> findRoleByUsername(String username);
}
我的CustomUserDetails类:
package com.sitename.security;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import com.sitename.domain.models.User;
public class CustomUserDetails extends User implements UserDetails {
private static final long serialVersionUID = 1L;
private List<String> userRoles;
public CustomUserDetails(User user, List<String> userRoles) {
super(user);
this.userRoles = userRoles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
String roles=StringUtils.collectionToCommaDelimitedString(userRoles);
return AuthorityUtils.commaSeparatedStringToAuthorityList(roles);
}
@Override
public String getPassword() {
return super.getPassword();
}
@Override
public String getUsername() {
return super.getUsername();
}
@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 false;
}
}
我的CustomUserDetailsService类:
package com.sitename.security;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.slf4j.*;
import com.sitename.domain.models.User;
import com.sitename.domain.repositories.UserRepository;
import com.sitename.domain.repositories.UserRoleRepository;
@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
Logger log = LoggerFactory.getLogger(CustomUserDetailsService.class);
private final UserRepository userRepository;
private final UserRoleRepository userRoleRepository;
@Autowired
public CustomUserDetailsService(UserRepository userRepository, UserRoleRepository userRoleRepository) {
this.userRepository = userRepository;
this.userRoleRepository = userRoleRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
log.info("Username entered: " + username);
if(user.equals(null)) {
log.info("User with username: " + username + " not found.");
throw new UsernameNotFoundException("No user found with username: " + username);
} else {
log.info("User found with username " + user.getUsername() + " and password " + user.getPassword());
List<String> userRoles = userRoleRepository.findRoleByUsername(username);
return new CustomUserDetails(user, userRoles);
}
}
}
Application.properties:
server.port:9000
spring.datasource.url = jdbc:mysql://localhost:3306/sitename
spring.datasource.username = root
spring.datasource.password = password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
主要课程:
package com.sitename;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.core.JdbcTemplate;
@SpringBootApplication
@EnableJpaRepositories(basePackages = "com.sitename.domain.repositories")
@EntityScan(basePackages = "com.sitename.domain.models")
public class WebsiteApplication {
private static final Logger log = LoggerFactory.getLogger(WebsiteApplication.class);
public static void main(String[] args) {
SpringApplication.run(WebsiteApplication.class, args);
}
}
我认为Hibernate查询可能会出错,因为“where username =?”日志的一部分,而不是username =“test”,但我不知道HQL所以我可能在那里错了。
以下是我尝试登录时显示的日志部分:
Hibernate: select user0_.id as id1_1_, user0_.email as email2_1_, user0_.enabled as enabled3_1_, user0_.password as password4_1_, user0_.username as username5_1_ from users user0_ where user0_.username=?
[2m2016-03-12 16:41:37.487[0;39m [32m INFO[0;39m [35m3420[0;39m [2m---[0;39m [2m[nio-9000-exec-8][0;39m [36mc.d.security.CustomUserDetailsService [0;39m [2m:[0;39m Username entered: test
[2m2016-03-12 16:41:37.487[0;39m [32m INFO[0;39m [35m3420[0;39m [2m---[0;39m [2m[nio-9000-exec-8][0;39m [36mc.d.security.CustomUserDetailsService [0;39m [2m:[0;39m User found with username test and password $2a$10$Lrp4kzL12tC.p0Ut7i92oeZzXn9WCplba1iPoJxAXRysxQ2dwvFxq
Hibernate: select userrole0_.role as col_0_0_ from user_roles userrole0_ cross join users user1_ where user1_.username=? and userrole0_.id=user1_.id
我还注意到successHandler()方法在启动时运行(它出现在日志中) - 不确定这是否正常。
非常感谢您的帮助!