我将在春季启动应用程序上实现spring security。为此,我通常会关注Spring boot and Spring Security integration for Rest API's并在SpringSecurity : Authenticate User with Custom UserDetailsService处获得详细信息。
实体:
User
和Role
在数据库中创建3个表(user
,role
&user_roles
)
User
package com.maxpro.entity;
import javax.persistence.*;
import java.util.Set;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String username;
private String password;
private boolean enabled;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
// getters, setters & toString
}
Role
package com.maxpro.entity;
import javax.persistence.*;
import java.util.Set;
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String role;
@ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
private Set<User> users;
// getters, setters & toString
}
存储库:
UserRepository
package com.maxpro.repository;
import com.maxpro.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository("userRepository")
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
配置:
WebSecurityConfigurer
使用WebUserDetailsService
自定义身份验证构建器
WebSecurityConfigurer
package com.maxpro.security;
import com.maxpro.repository.UserRepository;
import com.maxpro.security.service.WebUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private UserRepository userRepository;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsServiceBean());
}
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return new WebUserDetailsService(userRepository);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/css/**", "/img/**", "/js/**").permitAll()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/**").hasAuthority("ADMIN")
.antMatchers("/user/**").hasAuthority("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("username").passwordParameter("password").permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/")
// .and()
// .exceptionHandling().accessDeniedPage("/403")
// .and()
// .csrf();
;
}
}
WebUserDetailsService
package com.maxpro.security.service;
import com.maxpro.entity.Role;
import com.maxpro.entity.User;
import com.maxpro.repository.UserRepository;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import javax.transaction.Transactional;
import java.util.HashSet;
import java.util.Set;
@Transactional
public class WebUserDetailsService implements UserDetailsService {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(WebUserDetailsService.class);
private UserRepository userRepository;
public WebUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
User user = userRepository.findByUsername(username);
if (user == null) {
LOGGER.debug("user not found with the provided username");
return null;
}
LOGGER.debug(" user from username " + user.toString());
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), getAuthorities(user));
}
catch (Exception e){
throw new UsernameNotFoundException("User not found");
}
}
private Set<GrantedAuthority> getAuthorities(User user){
Set<GrantedAuthority> authorities = new HashSet<>();
for(Role role : user.getRoles()) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRole());
authorities.add(grantedAuthority);
}
LOGGER.debug("user authorities are " + authorities.toString());
return authorities;
}
}
问题:有时可以进行身份验证,有时则无法进行身份验证。为什么呢?
问题: loadUserByUsername()
自定义身份验证构建器中的WebUserDetailsService
是否有任何问题?
注意:我发现username
已传递到loadUserByUsername()
课程中的WebUserDetailsService
。我认为即使我将正确的用户名传递给存储库,UserRepository
也会返回null User
。
资源:这是Github上的代码。