SpringSecurity5(2-自定义用户信息)

打印 上一主题 下一主题

主题 1814|帖子 1814|积分 5442

设置文件自定义用户名和密码
  1. spring:
  2.   security:
  3.     user:
  4.       name: root    #通过配置文件,设置静态用户名
  5.       password: root    #配置文件,设置静态登录密码
复制代码
SecurityProperties
  1. @ConfigurationProperties(prefix = "spring.security")
  2. public class SecurityProperties {
  3.     public static final int BASIC_AUTH_ORDER = Ordered.LOWEST_PRECEDENCE - 5;
  4.     public static final int IGNORED_ORDER = Ordered.HIGHEST_PRECEDENCE;
  5.     public static final int DEFAULT_FILTER_ORDER = OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100;
  6.     private final Filter filter = new Filter();
  7.     private User user = new User();
  8.     public User getUser() {
  9.         return this.user;
  10.     }
  11.     public Filter getFilter() {
  12.         return this.filter;
  13.     }
  14.     public static class Filter {
  15.         private int order = DEFAULT_FILTER_ORDER;
  16.         private Set<DispatcherType> dispatcherTypes = new HashSet<>(
  17.                 Arrays.asList(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
  18.         public int getOrder() {
  19.             return this.order;
  20.         }
  21.         public void setOrder(int order) {
  22.             this.order = order;
  23.         }
  24.         public Set<DispatcherType> getDispatcherTypes() {
  25.             return this.dispatcherTypes;
  26.         }
  27.         public void setDispatcherTypes(Set<DispatcherType> dispatcherTypes) {
  28.             this.dispatcherTypes = dispatcherTypes;
  29.         }
  30.     }
  31.     public static class User {
  32.         private String name = "user";
  33.         private String password = UUID.randomUUID().toString();
  34.         private List<String> roles = new ArrayList<>();
  35.         private boolean passwordGenerated = true;
  36.         public String getName() {
  37.             return this.name;
  38.         }
  39.         public void setName(String name) {
  40.             this.name = name;
  41.         }
  42.         public String getPassword() {
  43.             return this.password;
  44.         }
  45.         public void setPassword(String password) {
  46.             if (!StringUtils.hasLength(password)) {
  47.                 return;
  48.             }
  49.             this.passwordGenerated = false;
  50.             this.password = password;
  51.         }
  52.         public List<String> getRoles() {
  53.             return this.roles;
  54.         }
  55.         public void setRoles(List<String> roles) {
  56.             this.roles = new ArrayList<>(roles);
  57.         }
  58.         public boolean isPasswordGenerated() {
  59.             return this.passwordGenerated;
  60.         }
  61.     }
  62. }
复制代码
SecuityProperties 会获取设置文件中的信息,UserDetailsServiceAutoConfiguration 在自动装配时获取 SecuityProperties 的属性信息
UserDetailsServiceAutoConfiguration
  1. @Configuration(proxyBeanMethods = false)
  2. @ConditionalOnClass(AuthenticationManager.class)
  3. @ConditionalOnBean(ObjectPostProcessor.class)
  4. @ConditionalOnMissingBean(
  5.     value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class },
  6.     type = { "org.springframework.security.oauth2.jwt.JwtDecoder", "org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector" })
  7. public class UserDetailsServiceAutoConfiguration {
  8.     private static final String NOOP_PASSWORD_PREFIX = "{noop}";
  9.     private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile("^\\{.+}.*$");
  10.     private static final Log logger = LogFactory.getLog(UserDetailsServiceAutoConfiguration.class);
  11.     @Bean
  12.     @ConditionalOnMissingBean(
  13.             type = "org.springframework.security.oauth2.client.registration.ClientRegistrationRepository")
  14.     @Lazy
  15.     public InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties,
  16.             ObjectProvider<PasswordEncoder> passwordEncoder) {
  17.         SecurityProperties.User user = properties.getUser();
  18.         List<String> roles = user.getRoles();
  19.         return new InMemoryUserDetailsManager(
  20.                 User.withUsername(user.getName()).password(getOrDeducePassword(user, passwordEncoder.getIfAvailable()))
  21.                         .roles(StringUtils.toStringArray(roles)).build());
  22.     }
  23.     private String getOrDeducePassword(SecurityProperties.User user, PasswordEncoder encoder) {
  24.         String password = user.getPassword();
  25.         if (user.isPasswordGenerated()) {
  26.             logger.info(String.format("%n%nUsing generated security password: %s%n", user.getPassword()));
  27.         }       
  28.         if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {
  29.             return password;
  30.         }
  31.         return NOOP_PASSWORD_PREFIX + password;
  32.     }
  33. }
复制代码
当容器中没有 AuthenticationManager、AuthenticationProvider、UserDetailsService 对应的实例类,且没有 org.springframework.security.oauth2.client.registration.ClientRegistrationRepository 时,会实例化 InMemoryUserDetailsManager 从而获取 SecurityProperties 的设置信息,加载用户信息在内存中
基于内存存储认证信息


  • 在 Spring Security 5.0 版本前,加密的 PasswordEncoder 接口默认实现类为 NoOpPasswordEncoder ,这个是可以不用加密的,直接利用明文密码存储。当前已经标注过时了。
  • 在 Spring Security 5.0 版本后 ,默认实现类改为了 DelegatingPasswordEncoder,这个实现类要求我们必须对加密后存储,假如不加密处置处罚则会报错。
根本利用
  1. @Configuration
  2. @Slf4j
  3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  4.     /**
  5.      * 密码编码器,密码不能明文存储
  6.      */
  7.     @Bean
  8.     public PasswordEncoder passwordEncoder() {
  9.         // 设置默认的加密方式,使用 BCryptPasswordEncoder 密码编码器,
  10.         // 该编码器会将随机产生的 salt 混入最终生成的密文中
  11.         return new BCryptPasswordEncoder();
  12.     }
  13.    
  14.     /**
  15.      * 定制基于 HTTP 请求的用户访问控制
  16.      */
  17.     @Override
  18.     protected void configure(HttpSecurity http) throws Exception {
  19.         /**
  20.          * fromLogin():表单认证
  21.          * httpBasic():弹出框认证
  22.          * authorizeRequests():身份认证请求
  23.          * anyRequest():所有请求
  24.          * authenticated():身份认证
  25.          */
  26.         http.httpBasic()
  27.                 .and()
  28.                 .authorizeRequests()
  29.                 // 其它任何请求访问都需要先通过认证
  30.                 .anyRequest()
  31.                 .authenticated();
  32.     }
  33.     /**
  34.     * 认证管理器:
  35.     * 1、认证信息提供方式(用户名、密码、当前用户的资源权限)
  36.     * 2、可采用内存存储方式,也可能采用数据库方式等
  37.     */
  38.     @Override
  39.     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  40.         // 用户信息存储在内存中
  41.         String password = passwordEncoder().encode("1234");
  42.         log.info("加密之后存储的密码:" + password);
  43.         auth.inMemoryAuthentication()
  44.             .withUser("admin")
  45.             .password(password)
  46.             .authorities("ADMIN");
  47.     }
  48.    
  49.     /**
  50.      * 定制一些全局性的安全配置,例如:不拦截静态资源的访问
  51.      */
  52.     @Override
  53.     public void configure(WebSecurity web) throws Exception {
  54.         // 静态资源的访问不需要拦截,直接放行
  55.         web.ignoring().antMatchers("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
  56.     }
  57. }
复制代码
加密处置处罚分析





UserDetailsService 自定义登录请求

在现实开发中,Spring Security 应该动态的从数据库中获取信息进行自定义身份认证,采用数据库方式进行身份认证一样平常需要实现两个核心接口 UserDetailsService 和 UserDetails
UserDetailService 接口

该接口只有一个方法 loadUserByUsername(),用于定义从数据库中获取指定用户信息的逻辑。假如未获取到用户信息,则需要手动抛出 UsernameNotFoundException 异常;假如获取到用户信息,则将该用户信息封装到 UserDetails 接口的实现类中并返回
  1. public interface UserDetailsService {
  2.     // 输入参数 username 是前端传入的用户名
  3.     UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
  4. }
复制代码
UserDetails 接口

UserDetails 接口定义了用于形貌用户信息的方法
[code]public interface UserDetails extends Serializable {    // 返回用户权限集合    Collection

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

玛卡巴卡的卡巴卡玛

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表