学习目标
- 常见安全性需求
- Spring security解决方案
- 基于Spring Security实现认证和授权的方法和实践
目录
- 安全性和Spring Security框架
- 用户认证及其实现方法
- 访问授权及其实现方法
安全性和Spring Security框架
用户认证(是谁)
权限控制(可以做啥)
单点登录
用户信息管理
跨域支持
敏感信息加解密
全局安全方法
跨站点请求伪造保护
Spring Security与单体应用:认证、授权
Spring Security与微服务架构:引入OAuth2协议、授权中心
用户认证实现方法
HTTP基础认证比较简单,没有定制的登录页面
1 2 3 4 5
| public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> { protected void configure(HttpSecurity http) throws Exception { http.httpBasic(); } }
|
表单认证
1 2 3 4 5 6 7 8 9
| public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> { protected void configure(HttpSecurity http) throws Exception { http.formLogin() //定制化登录界面和操作入口 .loginPage("/login.html")//自定义登录页面 .loginProcessingUrl("/action")//登录表单提交时的处理地址 .defaultSuccessUrl("/index");//登录认证成功后的跳转页面 } }
|
认证体系
配置文件
1 2 3 4 5
| spring: security: user: name: spring password: spring_password
|
内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Override protected void configure(AuthenticationManagerBuilder builder) throws Exception { builder.inMemoryAuthentication() .withUser("spring_user").password("password1").authorities("ROLE_USER") .and() .withUser("spring_admin").password("password2").authorities("ROLE_USER","ROLE_ADMIN"); } @Override protected void configure(AuthenticationManagerBuilder builder) throws Exception { builder.inMemoryAuthentication() .withUser("spring_user").password("password1").roles("USER") .and() .withUser("spring_admin").password("password2").roles("USER","ADMIN"); }
|
数据库
1 2 3 4 5 6 7 8 9 10
| @Autowired DataSource dataSource;
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource) .usersByUsernameQuery("select username, password, enabled from Users where username=?") .authoritiesByUsernameQuery("select username, authority from UserAuthorities ""'where username=?") .passwordEncoder(new BCryptPasswordEncoder()); }
|
PasswordEncoder
没有解密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public interface PasswordEncoder { String encode(CharSequence rawPassword); boolean matches(CharSequence rawPassword, String encodedPassword); default boolean upgradeEncoding(String encodedPassword) { return false; } }
public class BCryptPasswordEncoder implements PasswordEncoder { public String encode(CharSequence rawPassword) { String salt; if (random != null) { salt = BCrypt.gensalt(version.getVersion(), strength, random); } else { salt = BCrypt.gensalt(version.getVersion(), strength); } return BCrypt.hashpw(rawPassword.toString(), salt); } }
|
自定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class Sha512PasswordEncoder implements PasswordEncoder { @Override public String encode(CharSequence rawPassword) { return hashWithSHA512(rawPassword.toString()); } @Override public boolean matches(CharSequence rawPassword, String encodedPassword) { String hashedPassword = encode(rawPassword); return encodedPassword.equals(hashedPassword); } private String hashWithSHA512(String input) { StringBuilder result = new StringBuilder(); try { MessageDigest md = MessageDigest.getInstance("SHA-512"); byte [] digested = md.digest(input.getBytes()); for (int i = 0; i < digested.length; i++) { result.append(Integer.toHexString(0xFF & digested[i])); } } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Bad algorithm"); } return result.toString(); } }
|
加密通用模块
提供解密
- 加解密器(Encryptor)
- 键生成器(Key Generator)
1 2 3 4 5 6
| String salt = KeyGenerators.string().generateKey(); String password = "secret"; String valueToEncrypt = "HELLO"; BytesEncryptor e = Encryptors.standard(password, salt); byte [] encrypted = e.encrypt(valueToEncrypt.getBytes()); byte [] decrypted = e.decrypt(encrypted);
|
http.csrf().disable 关闭跨域请求伪造才可以通过idea.http测试接口
思考题
对于安全性而言,认证和授权分别解决了什么问题?如何解决?