1. Spring Security与Shiro?
- Spring Security是重量级框架,需要的依赖较多。但是与Spring无缝整合,权限功能更加完善。
- Shiro是轻量级框架,配置较为简便。但是在web环境下一些特定的需求需要手动编写代码实现。
- 推荐搭配:
- SSM+Shiro
- Springboot+Spring Security
2. Spring Security默认用户名:user;密码在控制台,每次项目启动都会变化。
3. Spring Security本质是一个过滤器链。有三个重要过滤器:
- FilterSecurityInterceptor:是一个方法级的权限过滤器, 基本位于过滤链的最底部。
public void invoke(FilterInvocation filterInvocation) throws IOException, ServletException {
if (this.isApplied(filterInvocation) && this.observeOncePerRequest) {
filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
} else {
if (filterInvocation.getRequest() != null && this.observeOncePerRequest) {
filterInvocation.getRequest().setAttribute("__spring_security_filterSecurityInterceptor_filterApplied", Boolean.TRUE);
}
InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
try {
filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
} finally {
super.finallyInvocation(token);
}
super.afterInvocation(token, (Object)null);
}
}
- ExceptionTranslationFilter:是个异常过滤器,用来处理在认证授权过程中抛出的异常。
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (IOException var7) {
throw var7;
} catch (Exception var8) {
Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(var8);
RuntimeException securityException = (AuthenticationException)this.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
if (securityException == null) {
securityException = (AccessDeniedException)this.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
}
if (securityException == null) {
this.rethrow(var8);
}
if (response.isCommitted()) {
throw new ServletException("Unable to handle the Spring Security Exception because the response is already committed.", var8);
}
this.handleSpringSecurityException(request, response, chain, (RuntimeException)securityException);
}
}
- UsernamePasswordAuthenticationFilter:对/login 的 POST 请求做拦截,校验表单中用户,密码。
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} else {
String username = this.obtainUsername(request);
username = username != null ? username : "";
username = username.trim();
String password = this.obtainPassword(request);
password = password != null ? password : "";
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
}
4. 过滤器加载过程:
- DelegatingFilterProxy初始化FilterChainProxy
- 找到FilterChainProxy,将所有过滤器加载
5. UserDetailsService接口:用来查询数据库用户名和密码。
- 创建类继承UsernamePasswordAuthenticationFilter,重写方法attemptAuthentication()、successfulAuthentication()和unsuccessfulAuthentication()
- 实现UserDetailsService接口,编写查询过程,返回User对象,这个User对象是安全框架提供的对象
6. PasswordEncoder接口:用来加密数据,
- BCryptPasswordEncoder 是 Spring Security 官方推荐的密码解析器,对bcrypt 强散列方法的具体实现。是基于 Hash 算法实现的单向加密。可以通过 strength 控制加密强度,默认 10。