赞
踩
Spring Security 是spring项目之中的一个安全模块
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
创建security配置类 并继承 WebSecurityConfigurerAdapter
@Autowired
private UserDetailsService userDetailsService;
/**
* 指定加密方式
* @return 使用BCrypt加密密码
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
/**
* 静态资源配置
*/
@Override
public void configure(WebSecurity web) throws Exception {
//swagger相关请求,不做拦截
// web.ignoring().antMatchers("/v2/api-docs",
// "/swagger-resources/configuration/ui",
// "//webjars*/**",
// "/swagger-resources/configuration/security",
// "/swagger*//**","/configuration/ui");
web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//允许根路径url的访问
.antMatchers("/").permitAll()
// .antMatchers("/swagger-ui.html").permitAll()
//其他请求拦截
.anyRequest().authenticated()
//
.and().formLogin().permitAll()
//登录成功后到swagger页面
.defaultSuccessUrl("/swagger-ui.html").permitAll()
//登出
.and().logout()
.logoutSuccessUrl("/login").permitAll()
//关闭csrf
.and().csrf().disable();
}
/**
* 跨域配置
* @return
*/
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
/*
同源配置,*表示任何请求都视为同源,
若需指定ip和端口可以改为如“localhost:8080”,
多个以“,”分隔;
*/
corsConfiguration.addAllowedOrigin("*");
//header,允许哪些header
corsConfiguration.addAllowedHeader("*");
//允许的请求方法,PSOT、GET等
corsConfiguration.addAllowedMethod("*");
//配置允许跨域访问的url
((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**", corsConfiguration);
return source;
}
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
//该接口只提供了一个 loadUserByUsername (通过用户名来加载用户)
//该方法用于将查询的用户加载到spring security中
//返回是 UserDetails
//用户信息,角色信息,用户角色对应关系的dao
@Autowired
private SysUserDao userDao;
@Autowired
private SysRoleDao sysRoleDao;
@Autowired
private SysUserRoleDao sysUserRoleDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser user = userDao.selectByUserName(username);
user.setSysRoles(sysUserRoleDao.selectByUserId(user.getId()));
// //在SysUser类中已经实现了 UserDetails 接口
return user;
}
从上面UserDetailsService 可以知道最终交给Spring Security的是UserDetails 。该接口是提供用户信息的核心接口。该接口实现仅仅存储用户的信息。后续会将该接口提供的用户信息封装到认证对象Authentication中去。
UserDetails 默认提供了一下方法:
//用户的权限集, 默认需要添加ROLE_ 前缀
Collection<? extends GrantedAuthority> getAuthorities();
//用户的加密后的密码, 不加密会使用{noop}前缀
String getPassword();
//应用内唯一的用户名
String getUsername();
//账户是否 未过期
boolean isAccountNonExpired();
//账户是否 未锁定
boolean isAccountNonLocked();
//凭证是否 未过期
boolean isCredentialsNonExpired();
//用户是否 可用
boolean isEnabled();
/**
* 权限集
* 重写 getAuthorities 方法,将用户的角色作为权限
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> auths = new ArrayList<>();
List<SysRole> sysRoleList = this.sysRoles;
//将自定义的角色作为权限
if (!CollectionUtils.isEmpty(sysRoleList)) {
sysRoleList.forEach(role -> {
auths.add(new SimpleGrantedAuthority(role.getCode()));
});
}
return auths;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
/**
* 账户是否未过期
* @return true: 未过期
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 账户是否未锁定
* @return true: 未锁定
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 凭证是否未过期
* @return true: 未过期
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 用户是否可用
* @return true: 可用
*/
@Override
public boolean isEnabled() {
return true;
}
如果以上的信息满足不了你使用,你可以自行实现扩展以存储更多的用户信息。比如用户的邮箱、手机号等等。通常我们使用其实现类:
org.springframework.security.core.userdetails.User
该类内置一个建造器UserBuilder 会很方便地帮助我们构建 UserDetails 对象
源码:
@Configuration
@ConditionalOnClass(AuthenticationManager.class)
@ConditionalOnBean(ObjectPostProcessor.class)
@ConditionalOnMissingBean({ AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class })
public class UserDetailsServiceAutoConfiguration {
private static final String NOOP_PASSWORD_PREFIX = "{noop}";
private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile("^\\{.+}.*$");
private static final Log logger = LogFactory.getLog(UserDetailsServiceAutoConfiguration.class);
@Bean
@ConditionalOnMissingBean(type = "org.springframework.security.oauth2.client.registration.ClientRegistrationRepository")
@Lazy //添加该注解表示该bean要延迟加载
public InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties, ObjectProvider<PasswordEncoder> passwordEncoder) {
SecurityProperties.User user = properties.getUser();
List<String> roles = user.getRoles();
return new InMemoryUserDetailsManager(
User.withUsername(user.getName()).password(getOrDeducePassword(user, passwordEncoder.getIfAvailable()))
.roles(StringUtils.toStringArray(roles)).build());
}
private String getOrDeducePassword(SecurityProperties.User user, PasswordEncoder encoder) {
String password = user.getPassword();
if (user.isPasswordGenerated()) {
logger.info(String.format("%n%nUsing generated security password: %s%n", user.getPassword()));
}
if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {
return password;
}
return NOOP_PASSWORD_PREFIX + password;
}
}
分析:
这个类只初始化了一个UserDetailsManager 类型的Bean。UserDetailsManager 类型负责对安全用户实体抽象UserDetails的增删查改操作。同时还继承了UserDetailsService接口。
明白了上面这些让我们把目光再回到UserDetailsServiceAutoConfiguration 上来。该类初始化了一个名为InMemoryUserDetailsManager 的内存用户管理器。该管理器通过配置注入了一个默认的UserDetails存在内存中,就是我们上面用的那个user ,每次启动user都是动态生成的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。