我的实例是 Spring Boot 我的项目,轻易一个 SpringBoot 我的项目都能够,先不启用 SpringSecurity。
创立一个 demoController,加办法:
@ResponseBody
@RequestMapping("wtf")
public String wtf(){return "WTF";}
运行我的项目,浏览器测试一下:
而后,pom 文件退出 SpringSecurity 的依赖后就启用 SpringSecurity 了。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
重新启动我的项目,拜访 wtf 测试一下:
阐明 SpringSecurity 起作用了,因为 Spring Security 的默认安全策略是对所有申请都必须通过平安验证,所以申请 wtf 须要首先通过身份认证能力拜访。这个时候他用的是默认的叫 InMemoryUserDetailsManager 的用户信息管理器来实现咱们上篇文章所说的用户管理工作的,他的默认用户为 user,明码在启动的过程中打印在了控制台:
用这个用户名、明码试一下:
能够拜访:
好的,咱们开始干活。
用户对象 Userdetails
首先须要有用户对象,用户对象须要有用户名、明码,SpringSecurity 要求用户对象实现接口:
org.springframework.security.core.userdetails。
代码如下,简略一点:
@Component
public class User implements UserDetails {
private String name;
private String password;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {return null;}
@Override
public String getPassword() {return password;}
@Override
public String getUsername() {return name;}
@Override
public boolean isAccountNonExpired() {return true;}
@Override
public boolean isAccountNonLocked() {return true;}
@Override
public boolean isCredentialsNonExpired() {return true;}
@Override
public boolean isEnabled() {return true;}
}
UserDetailsService
而后须要有咱们本人的 UserDetailsService。
创立一个用户 service 类、实现 UserDetailsService 接口的 loadUserByUsername 办法即可。
咱们创立一个用户名 user,明码:123456 的用户,示意以后零碎用户只有一个 user 用户、明码为 123456.
@Service
@Slf4j
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {log.info("Here we are in MyUserDetailsService====");
User user=new User();
user.setName("user");
user.setPassword("123456");
return user;
}
}
PasswordEncoder
实现明码解析器 PasswordEncoder 的 encode、matches 办法,这两个办法很好了解,encode 是对明码明文进行加密的,返回加密后的明码密文,matches 办法是用来验密的。
咱们不钻研加密算法,所以也就不加密了,理论利用的时候,我的项目中能够替换 encode 办法为加密算法即可。
@Service
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {return rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {return encode(rawPassword).equals(encodedPassword);
}
}
强调一下,UserDetailsService 和 PasswordEncoder 须要加注解 @Service,目标是注入 Spring Ioc 容器。
重新启动我的项目,这个时候控制台不会再打印下面的那个随机明码串了。
拜访 wtf,要求登录:
录入 user/123456:
登录胜利了!
阐明下面咱们本人创立的 UserDetailsService 和 PasswordEncoder 曾经开始工作了!!!
会不会感觉太简略了点?
简略剖析一下咱们本人实现的这两个类的失效起因。
Spring Security 在初始化 UsernamePassword… 的过程中会通过一个叫 InitializeUserDetailsManagerConfigurer 的配置类来初始化咱们上一篇文章说过的 AuthenticationProvider,通过上一篇文章咱们晓得绝大部分的用户验证工作都是这个 AuthenticationProvider 实现的。
咱们简略看一下 InitializeUserDetailsManagerConfigurer 的 configure 办法:
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {if (auth.isConfigured()) {return;}
UserDetailsService userDetailsService = getBeanOrNull(UserDetailsService.class);
if (userDetailsService == null) {return;}
PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
if (passwordEncoder != null) {provider.setPasswordEncoder(passwordEncoder);
}
if (passwordManager != null) {provider.setUserDetailsPasswordService(passwordManager);
}
provider.afterPropertiesSet();
auth.authenticationProvider(provider);
}
办法不长,能够看到首先要到 Spring Ioc 容器中去获取 UserDetailsService 和 PasswordEncoder,如果能获取到的话,就赋值给初始化好的 AuthenticationProvider。
因为咱们创立的 UserDetailsService 和 PasswordEncoder 都曾经通过注解注入到 SpringIoc 容器中了,所以,这里就能获取到。后续 AuthenticationProvider 在用户认证干活的时候能调用到咱们创立的这两个对象就不奇怪了!
上一篇 Spring Security 自定义用户认证过程(1)