Spring Security是一个可以为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组能够在Spring应用上下文中配置的Bean,为应用系统提供声明式的安全访问控制功能,减小了为企业系统安全控制编写大量重复代码的工做。css
权限控制是很是常见的功能,在各类后台管理里权限控制更是重中之重.在Spring Boot中使用 Spring Security 构建权限系统是很是轻松和简单的.下面咱们就来快速入门 Spring Security .在开始前咱们须要一对多关系的用户角色类,一个restful的controller.html
参考项目代码地址git
首先我默认你们都已经了解 Spring Boot 了,在 Spring Boot 项目中添加依赖是很是简单的.把对应的spring-boot-starter-***
加到pom.xml
文件中就好了github
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
简单的使用 Spring Security 只要配置三个类就完成了,分别是:web
这个接口中规定了用户的几个必需要有的方法spring
public interface UserDetails extends Serializable { //返回分配给用户的角色列表 Collection<? extends GrantedAuthority> getAuthorities(); //返回密码 String getPassword(); //返回账号 String getUsername(); // 帐户是否未过时 boolean isAccountNonExpired(); // 帐户是否未锁定 boolean isAccountNonLocked(); // 密码是否未过时 boolean isCredentialsNonExpired(); // 帐户是否激活 boolean isEnabled(); }
这个接口只有一个方法 loadUserByUsername,是提供一种用 用户名 查询用户并返回的方法。数据库
public interface UserDetailsService { UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException; }
这个内容不少,就不贴代码了,你们能够本身去看.segmentfault
咱们建立三个类分别继承上述三个接口api
/** * Created by Yuicon on 2017/5/14. * https://segmentfault.com/u/yuicon */ public class User implements UserDetails { private final String id; //账号,这里是我数据库里的字段 private final String account; //密码 private final String password; //角色集合 private final Collection<? extends GrantedAuthority> authorities; User(String id, String account, String password, Collection<? extends GrantedAuthority> authorities) { this.id = id; this.account = account; this.password = password; this.authorities = authorities; } //返回分配给用户的角色列表 @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @JsonIgnore public String getId() { return id; } @JsonIgnore @Override public String getPassword() { return password; } //虽然我数据库里的字段是 `account` ,这里仍是要写成 `getUsername()`,由于是继承的接口 @Override public String getUsername() { return account; } // 帐户是否未过时 @JsonIgnore @Override public boolean isAccountNonExpired() { return true; } // 帐户是否未锁定 @JsonIgnore @Override public boolean isAccountNonLocked() { return true; } // 密码是否未过时 @JsonIgnore @Override public boolean isCredentialsNonExpired() { return true; } // 帐户是否激活 @JsonIgnore @Override public boolean isEnabled() { return true; } }
UserDetailsService
/** * Created by Yuicon on 2017/5/14. * https://segmentfault.com/u/yuicon */ @Service public class UserDetailsServiceImpl implements UserDetailsService { // jpa @Autowired private UserRepository userRepository; /** * 提供一种从用户名能够查到用户并返回的方法 * @param account 账号 * @return UserDetails * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException { // 这里是数据库里的用户类 User user = userRepository.findByAccount(account); if (user == null) { throw new UsernameNotFoundException(String.format("没有该用户 '%s'.", account)); } else { //这里返回上面继承了 UserDetails 接口的用户类,为了简单咱们写个工厂类 return UserFactory.create(user); } } }
/** * Created by Yuicon on 2017/5/14. * https://segmentfault.com/u/yuicon */ final class UserFactory { private UserFactory() { } static User create(User user) { return new User( user.getId(), user.getAccount(), user.getPassword(), mapToGrantedAuthorities(user.getRoles().stream().map(Role::getName).collect(Collectors.toList())) ); } //将与用户类一对多的角色类的名称集合转换为 GrantedAuthority 集合 private static List<GrantedAuthority> mapToGrantedAuthorities(List<String> authorities) { return authorities.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); } }
/** * Created by Yuicon on 2017/5/14. * https://segmentfault.com/u/yuicon */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { // Spring会自动寻找实现接口的类注入,会找到咱们的 UserDetailsServiceImpl 类 @Autowired private UserDetailsService userDetailsService; @Autowired public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder // 设置UserDetailsService .userDetailsService(this.userDetailsService) // 使用BCrypt进行密码的hash .passwordEncoder(passwordEncoder()); } // 装载BCrypt密码编码器 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //容许跨域 @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("*") .allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS") .allowCredentials(false).maxAge(3600); } }; } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity // 取消csrf .csrf().disable() // 基于token,因此不须要session .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 容许对于网站静态资源的无受权访问 .antMatchers( HttpMethod.GET, "/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js", "/webjars/**", "/swagger-resources/**", "/*/api-docs" ).permitAll() // 对于获取token的rest api要容许匿名访问 .antMatchers("/auth/**").permitAll() // 除上面外的全部请求所有须要鉴权认证 .anyRequest().authenticated(); // 禁用缓存 httpSecurity.headers().cacheControl(); } }
使用 @PreAuthorize("hasRole('ADMIN')")
注解就能够了跨域
/** * 在 @PreAuthorize 中咱们能够利用内建的 SPEL 表达式:好比 'hasRole()' 来决定哪些用户有权访问。 * 需注意的一点是 hasRole 表达式认为每一个角色名字前都有一个前缀 'ROLE_'。因此这里的 'ADMIN' 其实在 * 数据库中存储的是 'ROLE_ADMIN' 。这个 @PreAuthorize 能够修饰Controller也可修饰Controller中的方法。 **/ @RestController @RequestMapping("/users") @PreAuthorize("hasRole('USER')") //有ROLE_USER权限的用户能够访问 public class UserController { @Autowired private UserRepository repository; @PreAuthorize("hasRole('ADMIN')")//有ROLE_ADMIN权限的用户能够访问 @RequestMapping(method = RequestMethod.GET) public List<User> getUsers() { return repository.findAll(); } }
Spring Boot中 Spring Security 的入门很是简单,很快咱们就能有一个知足大部分需求的权限系统了.而配合 Spring Security 的好搭档就是 JWT 了,二者的集成文章网络上也不少,你们能够自行集成.由于篇幅缘由有很多代码省略了,须要的能够参考参考项目代码