spring-Security《一》
源码介绍:
public interface UserDetailsService { UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException; }
里面返回一个UserDetails,来看下UserDetails里面是什么
public interface UserDetails extends Serializable { Collection<? extends GrantedAuthority> getAuthorities(); String getPassword(); 密码 String getUsername(); 用户名 boolean isAccountNonExpired(); 账号是否被过期 boolean isAccountNonLocked();账号是否被锁定 boolean isCredentialsNonExpired(); 证书(密码)是否过期 boolean isEnabled();账号是否被启用 }
UserDetails也是个接口,那么他肯定有实现类
里面果然有个User去实现它
看下User是什么东东
属性是与接口对应,有两个构造函数
用户名,密码,授权 public User(String username, String password, Collection<? extends GrantedAuthority> authorities) { this(username, password, true, true, true, true, authorities); } 就是那一堆属性构造方法了 public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) { if (username != null && !"".equals(username) && password != null) { this.username = username; this.password = password; this.enabled = enabled; this.accountNonExpired = accountNonExpired; this.credentialsNonExpired = credentialsNonExpired; this.accountNonLocked = accountNonLocked; this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities)); } else { throw new IllegalArgumentException("Cannot pass null or empty values to constructor"); } }
上面介绍了下账户授权,密码呀入口,别着急一丢丢来,慢慢爬 那么问题来了,既然是安全框架,密码不可能是明文吧,那么是怎么加密的呢 于是我们蒙蔽的找啊找,嘿哦看到一个密码Password名称的类
哎呦我操,你看看还真有,什么抽象的,策略的,加密的我都看不懂,就后面那俩Password的还认识下,点进去看看,上源码
public interface PasswordEncoder { /** * Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or * greater hash combined with an 8-byte or greater randomly generated salt. 人话就是推荐SHA-1或者8位的hash加盐的密码 */ String encode(CharSequence rawPassword); /** * Verify the encoded password obtained from storage matches the submitted raw * password after it too is encoded. Returns true if the passwords match, false if * they do not. The stored password itself is never decoded. * * @param rawPassword the raw password to encode and match * @param encodedPassword the encoded password from storage to compare with * @return true if the raw password, after encoding, matches the encoded password from * storage 人话就是原密码与加密的匹配 */ boolean matches(CharSequence rawPassword, String encodedPassword); /** * Returns true if the encoded password should be encoded again for better security, * else false. The default implementation always returns false. * @param encodedPassword the encoded password to check * @return true if the encoded password should be encoded again for better security, * else false. 人话就是对加密的密码再次编码 */ default boolean upgradeEncoding(String encodedPassword) { return false; } }
看一下他的实现类,真他妈离谱他妈给离谱开门了,离谱到家了,怎么那么多,老子看哪个,问问用过的老司机吧
点击去kankan
public String encode(CharSequence rawPassword) { return digest(rawPassword, saltGenerator.generateKey()); } 好家伙按位运算加盐加特殊字符¥拼接了, private String digest(CharSequence rawPassword, byte[] salt) { byte[] derived = SCrypt.generate(Utf8.encode(rawPassword), salt, cpuCost, memoryCost, parallelization, keyLength); String params = Long .toString(((int) (Math.log(cpuCost) / Math.log(2)) << 16L) | memoryCost << 8 | parallelization, 16); StringBuilder sb = new StringBuilder((salt.length + derived.length) * 2); sb.append("$").append(params).append('$'); sb.append(encodePart(salt)).append('$'); sb.append(encodePart(derived)); return sb.toString(); } //熟悉的呻吟bsae64编码 private byte[] decodePart(String part) { return Base64.getDecoder().decode(Utf8.encode(part)); } private String encodePart(byte[] part) { return Utf8.decode(Base64.getEncoder().encode(part)); }
测试一下:
随机盐saltGenerator.generateKey()这里已经生成了,就算密码一样,盐不一样结果也不一样
public String encode(CharSequence rawPassword) { return digest(rawPassword, saltGenerator.generateKey()); }
一点点学习,一丝丝进步。不懈怠,才不会被时代淘汰