Spring boot整合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>

配置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());
    }
  • 静态资源配置
		 /**
     * 静态资源配置
     */
    @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;
    }

UserDetailsService 接口

  UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
//该接口只提供了一个 loadUserByUsername (通过用户名来加载用户) 
//该方法用于将查询的用户加载到spring security中
//返回是 UserDetails
  • 实现 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;
    }

UserDetails 接口

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

//用户的权限集, 默认需要添加ROLE_ 前缀
Collection<? extends GrantedAuthority> getAuthorities();
//用户的加密后的密码, 不加密会使用{noop}前缀
String getPassword();
//应用内唯一的用户名
	String getUsername();
//账户是否 未过期
boolean isAccountNonExpired();
//账户是否 未锁定
	boolean isAccountNonLocked();
//凭证是否 未过期
	boolean isCredentialsNonExpired();
//用户是否 可用
	boolean isEnabled();
  • 自定义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;
    }

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

org.springframework.security.core.userdetails.User

该类内置一个建造器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;
    }
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值