当前位置:   article > 正文

Spring boot整合Security_spring-boot-starter-security

spring-boot-starter-security

Spring boot整合Security

概述

Spring Security 是spring项目之中的一个安全模块

  • WebSecurityConfigurerAdapter: 自定义Security策略
  • AuthenticationManagerBuilder: 自定义认证策略
  • @EnableWebSecurity: 开启WebSecurity模式
    Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)
认证 [Authentication]

身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。

授权 [Authorization]

授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。

添加依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4

配置Security

创建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());
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 静态资源配置
		 /**
     * 静态资源配置
     */
    @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/**");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 请求路径相关配置(拦截,授权)
 @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();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 跨域处理
  /**
     * 跨域配置
     * @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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

UserDetailsService 接口

  UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
//该接口只提供了一个 loadUserByUsername (通过用户名来加载用户) 
//该方法用于将查询的用户加载到spring security中
//返回是 UserDetails
  • 1
  • 2
  • 3
  • 4
  • 实现 UserDetailsService 接口
//用户信息,角色信息,用户角色对应关系的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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

UserDetails 接口

从上面UserDetailsService 可以知道最终交给Spring Security的是UserDetails 。该接口是提供用户信息的核心接口。该接口实现仅仅存储用户的信息。后续会将该接口提供的用户信息封装到认证对象Authentication中去。
UserDetails 默认提供了一下方法:

//用户的权限集, 默认需要添加ROLE_ 前缀
Collection<? extends GrantedAuthority> getAuthorities();
  • 1
  • 2
//用户的加密后的密码, 不加密会使用{noop}前缀
String getPassword();
  • 1
  • 2
//应用内唯一的用户名
	String getUsername();
  • 1
  • 2
//账户是否 未过期
boolean isAccountNonExpired();
  • 1
  • 2
//账户是否 未锁定
	boolean isAccountNonLocked();
  • 1
  • 2
//凭证是否 未过期
	boolean isCredentialsNonExpired();
  • 1
  • 2
//用户是否 可用
	boolean isEnabled();
  • 1
  • 2
  • 自定义class实现 UserDetails 接口对应的方法
    /**
     * 权限集
     * 重写 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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

如果以上的信息满足不了你使用,你可以自行实现扩展以存储更多的用户信息。比如用户的邮箱、手机号等等。通常我们使用其实现类:

org.springframework.security.core.userdetails.User
  • 1

该类内置一个建造器UserBuilder 会很方便地帮助我们构建 UserDetails 对象

UserDetailsServiceAutoConfiguration

源码:

@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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

分析:
这个类只初始化了一个UserDetailsManager 类型的Bean。UserDetailsManager 类型负责对安全用户实体抽象UserDetails的增删查改操作。同时还继承了UserDetailsService接口。
明白了上面这些让我们把目光再回到UserDetailsServiceAutoConfiguration 上来。该类初始化了一个名为InMemoryUserDetailsManager 的内存用户管理器。该管理器通过配置注入了一个默认的UserDetails存在内存中,就是我们上面用的那个user ,每次启动user都是动态生成的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/701993
推荐阅读
相关标签
  

闽ICP备14008679号