@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType(“application/json;charset=utf-8”);
PrintWriter out = resp.getWriter();
out.write(“logout success”);
out.flush();
}
})
.permitAll()
.and()
2.5、方法安全
上面介绍的认证与授权都是基于 URL 的,也可以通过注解来灵活地配置方法安全,要使用相关注解,首先要通过@EnableGloba!MethodSecurity 注解开启基于注解的安全配置:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
-
prePostEnabled=true会解锁@PreAuthorize和@PostAuthorize两个注解,@PreAuthorize会在执行方法前验证,@PostAuthorize会在执行方法后验证。
-
securedEnabled=true会解锁@Secured 注解。
@Service
public class MethodService {
//示访问该方法需要 ADMIN 角色
@Secured(“ROLE ADMIN”)
public String admin () {
return "hello admin ";
}
//访问该方法既需要ADMIN角色又需要USER角色
@PreAuthorize(“hasRole (‘ADMIN’) and hasRole ('USER ')”)
public String user(){
return “Hello User”;
}
//访问该方法需要ADMIN 或 USER角色
@PreAuthorize(“hasAnyRole(‘ADMIN’,‘USER’)”)
public String any(){
return “Hello Every One”;
}
}
3.1、加密方案
密码加密一般会用到散列函数,又称散列算法、哈希函数,这是一种从任何数据中创建数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来,然后将数据打乱混合,重新创建一个散列值。散列值通常用一个短的随机字母和数字组成的字符串来代表。好的散列函数在输入域中很少出现散列冲突。在散列表和数据处理中,不抑制冲突来区别数据会使得数据库记录更难找到。我们常用的散列函数有 MD5 消息摘要算法、安全散列算法(Secure Hash Algorithm )。
123456 —MD5—> e10adc3949ba59abbe56e057f20f883e
实际上,上面的实例在现实使用中还存在着一个不小的问题。虽然 MD5 算法是不可逆的,但是因为它对同一个字符串计算的结果是唯一 的,所以一些人可能会使用“字典攻击”的方式来攻破 MD5 加密的系统。这虽然属于暴力解密,却十分有效,因为大多数系统的用户密码都不会很长。
为了解决这个问题,我们可以使用盐值加密“salt-source”,所谓加盐加密,是指在加密之前,为原文附上额外的随机值,再进行加密。具体实现方法并不固定。
3.2、 实践
Spring Security内置了密码加密机制,只需使用一个PasswordEncoder接口即可。
PasswordEncoder接口定义了encode和matches两个方法,当用数据库存储用户密码时,加密过程用 encode方法,matches方法用于判断用户登录时输入的密码是否正确。
Spring Security 还内置了几种常用的 PasswordEncoder 接口,例如, StandardPasswordEncoder中的常规摘要算法(SHA-256等)、BCryptPasswordEncoder加密,以及类似 BCrypt的慢散列加密Pbkdf2PasswordEncoder等,官方推荐使用BCryptPasswordEncoder。
配置密码加密非常简单:
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
同样可以自定义加密方式,例如不想使用推荐的BCryptPasswordEncoder,想使用其它的加密方法,例如MD5加密,很简单,我们自己实现一个PasswordEncoder,在配置中使用自定义的加密类即可。
public class Md5PasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
//省略md5加密过程
return md5String;
}
@Override
public boolean matches(CharSequence charSequence, String s) {
//省略比对过程
return false;
}
}
@Bean
PasswordEncoder passwordEncoder() {
return new Md5PasswordEncoder();
}
在真实项目中,用户的基本信息以及角色等都存储在数据库中,因此需要从数据库中获取数据进行认证。
4.1、数据库设计
一共三张表,分别是用户表、角色表、用户_角色关联表。
创建表并插入一些测试数据:
SET FOREIGN_KEY_CHECKS=0;
– Table structure for role
DROP TABLE IF EXISTS role
;
CREATE TABLE role
(
id
int(11) NOT NULL AUTO_INCREMENT,
rolename
varchar(50) NOT NULL COMMENT ‘角色名’,
note
varchar(255) NOT NULL COMMENT ‘角色描述’,
PRIMARY KEY (id
)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT=‘角色表’;
– Records of role
INSERT INTO role
VALUES (‘1’, ‘ROLE_ADMIN’, ‘管理员’);
INSERT INTO role
VALUES (‘2’, ‘ROLE_DBA’, ‘数据库管理员’);
INSERT INTO role
VALUES (‘3’, ‘