设置文件自定义用户名和密码
- spring:
- security:
- user:
- name: root #通过配置文件,设置静态用户名
- password: root #配置文件,设置静态登录密码
复制代码 SecurityProperties
- @ConfigurationProperties(prefix = "spring.security")
- public class SecurityProperties {
- public static final int BASIC_AUTH_ORDER = Ordered.LOWEST_PRECEDENCE - 5;
- public static final int IGNORED_ORDER = Ordered.HIGHEST_PRECEDENCE;
- public static final int DEFAULT_FILTER_ORDER = OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100;
- private final Filter filter = new Filter();
- private User user = new User();
- public User getUser() {
- return this.user;
- }
- public Filter getFilter() {
- return this.filter;
- }
- public static class Filter {
- private int order = DEFAULT_FILTER_ORDER;
- private Set<DispatcherType> dispatcherTypes = new HashSet<>(
- Arrays.asList(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
- public int getOrder() {
- return this.order;
- }
- public void setOrder(int order) {
- this.order = order;
- }
- public Set<DispatcherType> getDispatcherTypes() {
- return this.dispatcherTypes;
- }
- public void setDispatcherTypes(Set<DispatcherType> dispatcherTypes) {
- this.dispatcherTypes = dispatcherTypes;
- }
- }
- public static class User {
- private String name = "user";
- private String password = UUID.randomUUID().toString();
- private List<String> roles = new ArrayList<>();
- private boolean passwordGenerated = true;
- public String getName() {
- return this.name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPassword() {
- return this.password;
- }
- public void setPassword(String password) {
- if (!StringUtils.hasLength(password)) {
- return;
- }
- this.passwordGenerated = false;
- this.password = password;
- }
- public List<String> getRoles() {
- return this.roles;
- }
- public void setRoles(List<String> roles) {
- this.roles = new ArrayList<>(roles);
- }
- public boolean isPasswordGenerated() {
- return this.passwordGenerated;
- }
- }
- }
复制代码 SecuityProperties 会获取设置文件中的信息,UserDetailsServiceAutoConfiguration 在自动装配时获取 SecuityProperties 的属性信息
UserDetailsServiceAutoConfiguration
- @Configuration(proxyBeanMethods = false)
- @ConditionalOnClass(AuthenticationManager.class)
- @ConditionalOnBean(ObjectPostProcessor.class)
- @ConditionalOnMissingBean(
- value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class },
- type = { "org.springframework.security.oauth2.jwt.JwtDecoder", "org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector" })
- 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
- 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;
- }
- }
复制代码 当容器中没有 AuthenticationManager、AuthenticationProvider、UserDetailsService 对应的实例类,且没有 org.springframework.security.oauth2.client.registration.ClientRegistrationRepository 时,会实例化 InMemoryUserDetailsManager 从而获取 SecurityProperties 的设置信息,加载用户信息在内存中
基于内存存储认证信息
- 在 Spring Security 5.0 版本前,加密的 PasswordEncoder 接口默认实现类为 NoOpPasswordEncoder ,这个是可以不用加密的,直接利用明文密码存储。当前已经标注过时了。
- 在 Spring Security 5.0 版本后 ,默认实现类改为了 DelegatingPasswordEncoder,这个实现类要求我们必须对加密后存储,假如不加密处置处罚则会报错。
根本利用
- @Configuration
- @Slf4j
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- /**
- * 密码编码器,密码不能明文存储
- */
- @Bean
- public PasswordEncoder passwordEncoder() {
- // 设置默认的加密方式,使用 BCryptPasswordEncoder 密码编码器,
- // 该编码器会将随机产生的 salt 混入最终生成的密文中
- return new BCryptPasswordEncoder();
- }
-
- /**
- * 定制基于 HTTP 请求的用户访问控制
- */
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- /**
- * fromLogin():表单认证
- * httpBasic():弹出框认证
- * authorizeRequests():身份认证请求
- * anyRequest():所有请求
- * authenticated():身份认证
- */
- http.httpBasic()
- .and()
- .authorizeRequests()
- // 其它任何请求访问都需要先通过认证
- .anyRequest()
- .authenticated();
- }
- /**
- * 认证管理器:
- * 1、认证信息提供方式(用户名、密码、当前用户的资源权限)
- * 2、可采用内存存储方式,也可能采用数据库方式等
- */
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- // 用户信息存储在内存中
- String password = passwordEncoder().encode("1234");
- log.info("加密之后存储的密码:" + password);
- auth.inMemoryAuthentication()
- .withUser("admin")
- .password(password)
- .authorities("ADMIN");
- }
-
- /**
- * 定制一些全局性的安全配置,例如:不拦截静态资源的访问
- */
- @Override
- public void configure(WebSecurity web) throws Exception {
- // 静态资源的访问不需要拦截,直接放行
- web.ignoring().antMatchers("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
- }
- }
复制代码 加密处置处罚分析
UserDetailsService 自定义登录请求
在现实开发中,Spring Security 应该动态的从数据库中获取信息进行自定义身份认证,采用数据库方式进行身份认证一样平常需要实现两个核心接口 UserDetailsService 和 UserDetails
UserDetailService 接口
该接口只有一个方法 loadUserByUsername(),用于定义从数据库中获取指定用户信息的逻辑。假如未获取到用户信息,则需要手动抛出 UsernameNotFoundException 异常;假如获取到用户信息,则将该用户信息封装到 UserDetails 接口的实现类中并返回- public interface UserDetailsService {
- // 输入参数 username 是前端传入的用户名
- UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
- }
复制代码 UserDetails 接口
UserDetails 接口定义了用于形貌用户信息的方法
[code]public interface UserDetails extends Serializable { // 返回用户权限集合 Collection |