Case1、简单的登录:

SpringSecurity自带有一套基于内存的验证,这样我们仅需要实现简单的登录功能的时候,就不需要额外去创建数据库了。在 SpringSecurityConfig 类中,加入如下方法:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().  // 使用基于内存的认证方式
                passwordEncoder(new BCryptPasswordEncoder()).  // 设置密码的加密方式
                withUser("admin").  // 设置用户名称
                password(new BCryptPasswordEncoder().encode("123456")).  // 设置密码
                roles("ADMIN");  // 自定义该用户的角色
    }
    ...
}

Case2、有指定的角色,每个角色有指定的权限:

即便是简单的登录,也可能会遇到有一些资源需要管理员角色才能访问。所以我们来看看如何限定一个资源只能被管理员用户访问。在configure方法中,增加一个普通用户,代码如下:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().
            passwordEncoder(new BCryptPasswordEncoder()).
            withUser("admin").
            password(new BCryptPasswordEncoder().encode("123456")).
            roles("ADMIN");
 
    auth.inMemoryAuthentication().
            passwordEncoder(new BCryptPasswordEncoder()).
            withUser("user").
            password(new BCryptPasswordEncoder().encode("user")).
            roles("USER");
}

复制

在DemoController类中增加一个接口,并指定这个接口只能被admin角色的用户访问。代码如下:

@RestController
// 开启验证
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class DemoController {
 
    // 指定该接口只能被ADMIN角色的用户访问,ROLE_这个前缀是固定要写的
    @PreAuthorize("hasRole('ROLE_ADMIN')")  
    @GetMapping("/roleAuth")
    public String role(){
        return "admin auth";
    }
    ...
}

@PreAuthorize里的表达式可以使用 and 、or这种运算符,例如:

@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_ROOT')")

复制

除了@PreAuthorize注解外,还有:

  • @PostAuthorize:方法执行完后再进行角色验证
  • @PreFilter:方法执行前进行验证,用于过滤集合类型的参数或返回值
  • @PostFilter:方法执行后进行验证,用于过滤集合类型的参数或返回值

Case3、自定义密码加密:

我们可以自定义自己的加密方式去做密码的加密及匹配,我这里使用MD5作为演示。首先创建一个 MyPasswordEncoder 类并实现 PasswordEncoder 接口。具体代码如下:

package org.zero.security.securitydemo.encoder;
 
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.DigestUtils;
 
/**
 * @program: security-demo
 * @description: 自定义密码加密器
 * @author: 01
 * @create: 2018-09-07 21:43
 **/
public class MyPasswordEncoder implements PasswordEncoder {
 
    @Override
    public String encode(CharSequence charSequence) {
        // 使用Spring自带的工具进行MD5加密
        return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
    }
 
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {        
        // 验证密码加密后是否一致
        return encode(rawPassword).equals(encodedPassword);
    }
}

使用我们自己自定义的密码加密器,修改configure方法的代码如下:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().
            passwordEncoder(new MyPasswordEncoder()).
            withUser("admin").
            password(new MyPasswordEncoder().encode("123456")).
            roles("ADMIN");
 
    auth.inMemoryAuthentication().
            passwordEncoder(new MyPasswordEncoder()).
            withUser("user").
            password(new MyPasswordEncoder().encode("user")).
            roles("USER");
}

Case4、参数验证:

通过@PreAuthorize注解,我们可以在方法执行前,进行权限参数的验证。例如我要验证id小于时,且username参数的值和当前登录的用户名一致。代码如下:

@PreAuthorize("#id<10 and principal.username.equals(#username)")
@GetMapping("/check_info")
public String checkInfo(Integer id, String username) {
    return "success";
}

复制

如果参数是一个对象也可以进行校验,代码如下:

@PreAuthorize("#user.username.equals('admin')")
@GetMapping("/check_user")
public String checkUser(User user) {
    return "success";
}

复制


总结

优点:

  • 提供了一套安全框架,而且这个框架是可以用的
  • 提供了很多用户认证功能,实现相关接口即可,节约大量开发工作
  • 基于Spring,使得它易于集成到Spring项目中,且封装了许多方法

缺点:

  • 配置文件多,角色被 “编码” 到配置文件或源文件中,RBAC不明显
  • 对于系统中用户、角色、权限之间的关系,没有可操作的界面
  • 大数据量的情况下,几乎不可用