我不太喜欢Spring Security。我正在一个Spring Boot项目(实现一些REST Web服务)中,其他人已经实现了Spring Security来执行身份验证。看起来不错,但我对它的工作原理(体系结构)有些怀疑。
所以基本上我有以下课程:
1)用户是我代表用户的模型类:
@Entity @Table(name = "user", uniqueConstraints = { @UniqueConstraint(columnNames = {"email","username"}) }) public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; //@Pattern(regexp="\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",flags = Pattern.Flag.CASE_INSENSITIVE) @Column(name="email", unique=true,nullable=false) private String email; @NotNull @Column(name="registration_date",nullable=false) private Date registration_date; @NotBlank @Column(name="username",nullable = false,unique=true) private String username; @NotBlank @Column(name="password",nullable = false) private String password; @Column(name="enabled", nullable = false) private boolean enabled; @ManyToMany @JoinTable(name = "user_user_roles", joinColumns = { @JoinColumn(name = "id_user", updatable = true) }, inverseJoinColumns = { @JoinColumn(name = "id_roles", updatable = true)}, uniqueConstraints={@UniqueConstraint(columnNames = {"id_user","id_roles"})} ) @Cascade({CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH,CascadeType.PERSIST, CascadeType.SAVE_UPDATE}) private ListuserRoles; // CONSTRUCTOR, GETTER AND SETTER METHODS }
这是一个休眠类,提供与加入user_user_roles包含用户ROOL有关特定用户(我觉得列表数据库表ROLE_ADMIN,ROLE_USER,etcetc)
2)然后我有CustomUserDetails类,该类扩展了User并实现了Spring Security UserDetails接口。
因此,这意味着它将包含与特定用户有关的所有信息(其中包括与此用户相关联的角色),并实现在UserDetails接口中声明的所有方法。
public class CustomUserDetails extends User implements UserDetails { private static final long serialVersionUID = 1L; public CustomUserDetails(User user){ super(user); } @Override public Collection extends GrantedAuthority> getAuthorities() { Setauthorities = new HashSet (); for(UserRole role : this.getUserRoles() ){ GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getName()); authorities.add(grantedAuthority); } return authorities; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } @Override public String getUsername() { return super.getUsername(); } }
在我看来,该类代表了Spring应用程序与Spring Security之间的桥梁(类似的东西带有与特定用户有关的角色信息,是吗?)。
在此类中,与用户角色列表有关的信息包含在扩展GrantedAuthority的通用对象的集合中。
我认为GrantedAuthority对象表示用户的角色(实际上是由role.getName()构建的,该字符串是表示当前用户角色的字符串)。这个推理正确吗?
基本上,以前的实现只返回与特定用户有关的GrantedAuthority的集合,对吗?
3)实现Spring Security UserDetailsService接口的CustomUserDetailsService类:
@Transactional @Service("customUserDetailsService") public class CustomUserDetailsService implements UserDetailsService{ @Autowired private UserDAO userDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userDao.findByUsername(username); if(user == null){ throw new UsernameNotFoundException("No user present with username: "+username); }else{ return new CustomUserDetails(user); } } }
基本上,这是一个仅实现loadUserByUsername(String username))方法的服务,该方法执行以下操作:
首先检索与用户(一个User对象)有关的信息,包括他的角色列表(List userRoles)。
然后,使用此User对象构建先前的CustomUserDetails,该CustomUserDetails用于检索与该用户相关的GrantedAuthority的集合。
所有这些推理都正确吗?
然后我还有这个WebSecurityConfig,我认为它代表了Spring Security的配置:
@Configuration @EnableWebSecurity @ComponentScan(basePackageClasses = CustomUserDetailsService.class) @EnableAutoConfiguration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { } }
这对我来说太晦涩了。到底是什么?
据我了解,它通过** @ EnableWebSecurity **来启用REST Web服务安全性。
但是,为什么要自动装配UserDetailsService Bean?
究竟该空的configure()方法是什么呢?
您的推论是正确的。
Spring-security要求您创建一个实现UserDetailsService的服务。它期望服务具有loadUserByUsername方法,该方法返回用户对象(需要实现Spring的User类)。该用户实例用于获取权限,以便您可以限制对某些URL的访问。即,您可以将URL访问映射到具有特定权限的用户。
就空方法configure()而言,它用于url的身份验证和授权(如上所述)以及其他一些事情。实际上,就安全性而言,这是最灵活,最强大的方法。
我项目的config方法如下所示:
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/","/static/**").permitAll() .mvcMatchers("/admin").access("hasAuthority('ROLE_ADMIN')") .mvcMatchers("/employees").access("hasAuthority('ROLE_STAFF')") .anyRequest().authenticated() .and() .httpBasic() .and() .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .and() .logout().logoutSuccessUrl("/") .and() .headers().contentSecurityPolicy("default-src 'self' " + "https://ajax.googleapis.com " + "https://cdnjs.cloudfare.com " + "style-src 'self' 'unsafe-inline' "); }
上面的例子
确保所有请求都经过身份验证和授权。
允许免费访问静态资源
确保只有角色ADMIN的用户才能访问url / admin
设置基本登录提示以进行身份验证
设置注销网址
设置基于cookie的CSRF令牌系统
设置内容安全策略
要了解有关所有春季安全性功能的更多信息,我强烈建议您使用这些资源。
Rob Winch的出色视频演示(Spring Security项目负责人)
具有良好范例的网站
示例代码仓库