用户认证的流程:
Spring Security支持多种用户认证的方式,最常用的是基于用户名和密码的用户认证方式,其认证流程如下图所示:
1. 为什么定义的成功处理地址defaultSuccessUrl没生效:
如果自定义了用户认证成功处理器,则在Spring Security配置类中通过http.formlogin().defaultSuccessUrl(" URL")来指定的默认认证成功后请求的URL配置并不会对自定义的用户认证成功处理器有效,因为该配置只对Spring Security默认的用户认证成功处理器有效。要想使得自定义的用户认证成功之后自动请求指定的URL,则需要在自定义的用户认证成功处理器中通过设置defaultTargetUrl参数的值的方式来实现。
2. 假如用户登录后,在一定时间如果有操作,怎样设计一个延长登录有效时间。没有一定时间没有操作,不延长登录时间。(jwt前后端分离如何设计永久登录)
使用refresh_token机制:如设置refresh_token有效时间为3天,access_token时间为1天,如果一天过后用户有操作,将使用refresh_token刷新access_token并生成新的refresh_token,此时refresh_token重新计算三天有效期,也就延长了登录时间。永久登录同理,将refresh_token设置永不过期即可。
3. addFilterBefore使用介绍:
在UsernamePasswordAuthenticationFilter之前执行jwtAuthorizationFilter;
// 用户权限的验证 在 beforeFilter 之前添加 filter
http.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class); // JWT Filter
4. 除了使用@PreAuthorize控制方法权限,还可以添加全局拦截动态认证:
// 认证的逻辑
HttpSecurity http
.access("@rbacauthorityservice.hasPermission(request,authentication)") // RBAC 动态 url 认证
5. JwtToken认证方式,在无状态,怎么实现注销操作?
每次登陆,生成 JwtToken放到 Redis 数据库里边,调用接口的时候,先查有没有这个 token,注销时把 token 删除。利用Redis判定用户token是否存在,验证用户是否已注销。
6. AuthenticationManage、AuthenticationProvider之间的关系:
1、在UsernamePasswordAuthenticationFilter的attemptAuthentication()方法中,调用AuthenticationManager进行认证
2、AuthenticationManager接收Authentication对象作为参数,并通过authenticate方法对其进行验证(实际由其实现类ProviderManager完成)
3、在ProviderManager的authenticate方法中,轮训成员变量List<AuthenticationProvider> providers。该providers中如果有一个AuthenticationProvider的supports函数返回true,那么就会调用该AuthenticationProvider的authenticate函数认证,如果认证成功则整个认证过程结束。如果不成功,则继续使用下一个合适的AuthenticationProvider进行认证,只要有一个认证成功则为认证成功。
4、UsernamePasswordAuthenticationToken实现了Authentication,主要是将用户输入的用户名密码进行封装,并提供给AuthenticationManager进行验证,验证成功后,返回一个认证成功的UsernamePasswordAuthenticationToken对象。
AuthenticationProvider也是一个接口,包含两个函数authenticate和supports。当Spring Security默认提供的Provider不能满足需求的时候,可以通过实现AuthenticationProvider接口来扩展出不同的认证提供者。
AuthenticationManagerBuilder用于创建AuthenticationManager。 允许轻松构建内存身份验证,LDAP身份验证,基于JDBC的身份验证,添加UserDetailsService以及添加AuthenticationProvider。
参考:https://blog.csdn.net/shenchaohao12321/article/details/87721655
7. base64encode 一直出现特殊字符怎么办?(URL参数有时候因为安全问题,不用出现某些字符)
将其 hex 状态十六进制。
8. @PreAuthorize安全表达式hasRole、hasAuthority区别:
见我的博客:https://blog.csdn.net/qq_26878363/article/details/103632459
9. Spring当中很好用参考例子:supports方法来表示本provider提供的认证范围(学到新姿势了)
AuthenticationProvider->
boolean supports(Class<?> authentication);
10. 跨域预请求取消拦截(我记得OPTIONS不添加好像也是不会拦截的,在这里备份一下)
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll() //跨域预请求添加;
11. 获取用户真实IP的方法(识破反向代理,暂未验证哟,等有时间了验证。看起来应该可以)
/**
* 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
12. 链式编程:
public StudentBean setName(String name) {
this.name = name;
return this;
}
这段代码和传统的Bean区别就是我在set属性时候会返回一个this这样就达到了链式编程的效果
lombok其实已经提供该style,我们把这个bean改成lombok实现只需要加上一个@Accessors(chain = true)即可。
@Accessors(chain = true)
@Getter
@Setter
public class StudentBean {
private String name;
private int age;
}
参考文章:
https://blog.csdn.net/weixin_44516305/article/details/87860966(个人感觉这篇文章理解更清晰,里边还有自定义实现)