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不明显
- 对于系统中用户、角色、权限之间的关系,没有可操作的界面
- 大数据量的情况下,几乎不可用