您好 ,我是湘王 ,这是我的博客园 ,欢迎您来 ,欢迎您再来~
前面运行写好的代码之所以没有任何显示 ,是因为还没有对Spring Security进行配置 ,当然啥也不显示了 。这就好比你坐在车上 ,却不打开发动机 ,车子当然跑不起来 。所以咱们就来让它跑起来。不过在配置之前 ,有必要对Spring Security的登录流程做个大致了解 。
如果深入源码去了解,这个玩意及其复杂 ,但是没必要 ,知道它的机制就行了 。就好比你买车也不必把发动机拆开去看它是怎么工作的吧 。简单来说它就是下面这些步骤:
1 、Spring Security通过AuthenticationManager接口进行身份验证
2 、ProviderManager是AuthenticationManager的一个默认实现
3 、ProviderManager把验证工作委托给了AuthenticationProvider接口
4 、AuthenticationProvider的实现类DaoAuthenticationProvider会检查身份认证
5 、DaoAuthenticationProvider又把认证工作委托给了UserDetailsService接口
6 、自定义UserDetailsService类从数据库中获取用户账号 、密码 、角色等信息,然后封装成UserDetails返回
7 、使用Spring Security还需要自定义AuthenticationProvider接口 ,获取用户输入的账号、密码等信息 ,并封装成Authentication接口
8 、将UserDetails和Authentication进行比对,如果一致就返回UsernamePasswordAuthenticationToken ,否则抛出异常
下面是认证流程图:
首先重写loadUserByUsername:
因为UserDetailsService返回了封装的UserDetails ,所以需要再自定义AuthenticationProvider返回Authentication接口:
/**
* 自定义登录验证
*
* @author 湘王
*/
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取表单输入中返回的用户名
String username = (String) authentication.getPrincipal();
// 获取表单中输入的密码
String password = (String) authentication.getCredentials();
// 这里调用我们的自己写的获取用户的方法
UserDetails userInfo = customUserDetailsService.loadUserByUsername(username);
if (userInfo == null) {
System.out.println("user is not exist");
throw new UsernameNotFoundException("user is not exist");
}
PasswordEncoder passwordEncoder = new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
};
// 采用简单密码验证
if (!passwordEncoder.matches(password, userInfo.getPassword())) {
System.out.println("user or password error");
throw new BadCredentialsException("user or password error");
}
Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
// 构建返回的用户登录成功的token
return new UsernamePasswordAuthenticationToken(userInfo, password, authorities);
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
接着来实现实现WebSecurityConfigurerAdapter ,它通过重写WebSecurityConfigurerAdapter中的相关方法(一般是configurer)来自定义配置 。WebSecurityConfigurerAdapter主要做几件事:
1 、初始化
2、开启Security
3 、配置各种过滤器 ,实现验证过滤器链
下面是它的代码:
/**
* spring security验证配置
*
* @author 湘王
*/
// 配置类
@Configuration
// 开启Security服务
@EnableWebSecurity
// 开启全局Securtiy注解
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private CustomAuthenticationProvider authenticationProvider;
// 自定义的登录验证逻辑
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
// 控制逻辑
@Override
protected void configure(HttpSecurity http) throws Exception {
// 执行UsernamePasswordAuthenticationFilter之前添加拦截过滤
http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests()
.anyRequest().authenticated()
// 设置自定义认证成功 、失败及登出处理器
.and().formLogin().loginPage("/login")
.and().cors()
.and().csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
// 设置拦截忽略文件夹 ,可以对静态资源放行
web.ignoring().antMatchers("/css/**", "/js/**");
}
}
接着用postman进行测试:
回顾整个调用过程 ,它的时序图是:
但是等等:好像除了/login ,其他方法都不能正常访问!
感谢您的大驾光临!咨询技术、产品 、运营和管理相关问题 ,请关注后留言 。欢迎骚扰 ,不胜荣幸~
声明:本站所有文章,如无特殊说明或标注 ,均为本站原创发布 。任何个人或组织 ,在未征得本站同意时,禁止复制 、盗用 、采集 、发布本站内容到任何网站 、书籍等各类媒体平台 。如若本站内容侵犯了原著者的合法权益 ,可联系我们进行处理 。