Spring Security(一)(基本介绍及使用)

前言

学习security,记录下

正文

1. 简介

Spring Security是为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了完整的安全性解决方案,可以在Web请求级别和方法调用级别处理身份认证和授权充分利用了Spring IOC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能。

2. 模块
  • ACL 支持通过访问控制列表(access control list,ACl)为域对象提供安全性
  • Aspects 一个很小的模块,当使用Spring Security注解时,会使用基于AspectJ的切面
  • CAS Client 提供与CAS集成的功能
  • Configuration 包含XML和JAVA配置的功能支持
  • Core 基本功能库
  • Cryptography 提供加密和密码编码相关功能
  • LDAP 基于LDAP认证
  • OpenID 支持使用OpenID进行集中式认证
  • Remoting 提供了对Spring Remoting的支持
  • Tag Library Security的JSP标签库
  • Web 提供了Security基于Filter的Wen安全性支持
    备注:
    应用程序的类路径下至少需要包括Core和Configuration模块,Web应用下需要加入Web应用
3. Demo(基于SpringBoot+SpringSecurity+MySql)
3.1. pom.xml
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        </dependency>
        <!--支持热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <executable>true</executable>
                    <fork>true</fork><!--注意要修改这里,支持热部署-->
                </configuration>
            </plugin>
        </plugins>
    </build>
3.2. config

配置类WebSecurityConfig继承WebSecurityConfigurerAdapter

@Configuration
@EnableWebSecurity//启用安全
@EnableGlobalMethodSecurity(securedEnabled = true,jsr250Enabled = true,prePostEnabled = true)//开启注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}

重载configure(HttpSecurity)方法,通过重载,配置如何通过拦截器保护请求

@Override
protected void configure(HttpSecurity http) throws Exception {
             http.formLogin().loginPage("/login").loginProcessingUrl("/auth/login").defaultSuccessUrl("/index")//指定登录页面以及登录成功后的跳转页面
                .and()
                .logout().logoutSuccessUrl("/login")//指定登出后的页面
                .and()
                .authorizeRequests()//拦截请求配置
                .antMatchers("/css/**", "/js/**","/images/**", "/static/**").permitAll()//允许访问静态资源
                .antMatchers("/login","/auth/login").permitAll()  //  premitAll()不做拦截
                .antMatchers("/index").authenticated()   //authenticated()  必须登录后可见
                .antMatchers("/hello").access("hasRole('ADMIN')") //必须拥有ADMIN角色权限才可以访问
                .anyRequest().authenticated();
                //.and()
//              .rememberMe().tokenValiditySeconds(2419200).tokenRepository(persistentTokenRepository()).alwaysRemember(true);// 启用记住我
    }

重载configure(AuthenticationManagerBuilder)方法,通过重载,配置user-detail服务
重载configure(WebSecurity)方法,通过重载,配置Security的Filter链

3.3. 四种用户验证方式

上面提到了重载configure(AuthenticationManagerBuilder)方法,可以配置user-detail服务,这个方法决定用户的校验方式,一般来说有四种

  • 基于内存验证
auth.inMemoryAuthentication()
                  .withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN").and()
                      .withUser("test").password(passwordEncoder().encode("test")).roles("TEST");
  • 基于数据库验证
auth.jdbcAuthentication().dataSource(dataSource)
              .usersByUsernameQuery("select username,password,enabled from user where username = ?")
              .authoritiesByUsernameQuery("select username,rolename from role where username=?")
              .passwordEncoder(passwordEncoder());
  • 基于LDAP验证
auth.ldapAuthentication().userSearchFilter("{uid=0}").groupSearchFilter("member={0}");
  • 自定义用户服务
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());

这里customUserDetailsService必须实现UserDetailsService

@Component
@Slf4j
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByAccount(username);
        if (user==null){
            throw new AuthenticationCredentialsNotFoundException("authError");
        }
        Set<Role> roles = user.getRoles();
        List<GrantedAuthority> authorities = new ArrayList<>();
        roles.forEach(role-> authorities.addAll(AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_"+role.getName())));
        return new org.springframework.security.core.userdetails.User(user.getAccount(),user.getPassword(),authorities);
    }
}
3.4. 注解

三种不同的安全注解

  • 自带的@Secured注解(@EnableGlobalMethodSecurity中设置securedEnabled = true)
  • JSR-250的@RolesAllowed注解(@EnableGlobalMethodSecurity中设置jsr250Enabled = true)
  • 表达式驱动注解,@PreAuthorize、@PostAuthorize、@PreFilter、@PostFilter
    这里我们主要讲表达式驱动注解:
    @PreAuthorize 方法调用之前,基于表达式的计算结果来限制对方法的访问
    @PostAuthorize 方法调用之后,如果表达式的结果为false,则抛出异常
    @PreFilter 方法调用之前,过滤进入方法的输入值
    @PostFilter 方法调用之后,过滤方法的结果值
@Controller
@RequestMapping("/")
public class AuthController {

    @GetMapping("login")
    public String login (){
        return "login";
    }
    @GetMapping("index")
    public String index(){
        return "index";
    }
    @GetMapping("hello")
    @PreAuthorize("hasRole('ADMIN')")
    public String hello(){//必须拥有ADMIN权限的用户才可以进去
        return "hello";
    }
    @GetMapping("postAuth")
    @PostAuthorize("hasRole('TEST')")
    @ResponseBody
    public String  postAuth(){//可以进入但是没有TEST的权限的用户会报403错误
        return "postAuth";
    }
    @PostMapping("preFilter")
    @PreFilter(filterTarget="users", value="filterObject.id != null")
    @ResponseBody
    public String  preFilter(@RequestBody List<User> users){//进入方法后users的size为0
        return "preFilter";
    }
    @PostMapping("postFilter")
    @PostFilter(value="filterObject.id != null")
    @ResponseBody
    public List<User> postFilter(@RequestBody User user){//客户端拿到的是空的
        List<User> users = new ArrayList<User>();
        users.add(user);
        return users;
    }
}

总结

一些基本的功能以及介绍已经了解了,具体的使用还是需要投入到实际项目中,下面接着往下学习。
security是如何进行登录验证和权限控制的?

参考资料
参考代码

demo 地址

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容