当springsecurity的remember-me功能遇上用户名修改

前段时间决定使用springsecurity来做用户权限,springsecurity功能非常强大,而且配置灵活,足以满足一般的权限要求。其中有一个功能是remember-me,也就是自动登录,在参考网上的例子后也能正常实现基本要求,但是我们有个需求是需要变更用户名,在正常修改了用户信息后,session过期了再刷新页面便要重新登录,失去了自动登录功能。

经过分析后确定,就是因为用户名改了,所以cookie对应的数据库持久化token就无法使用了(在这里我们使用的是PersistentTokenRepository,可以持久化token),所以现在要解决的就是在用户名修改后也要更新页面的cookie,而且需要保存新的token,下面是代码实现。

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @Autowired
    @Lazy
    private RememberMeServices rememberMeService;

    @PostMapping("/bindPhone")
    public ReturnMsg bindPhone(@NotNull(message = "验证码不能为空") @Pattern(regexp = "^1234$", message = "验证码不正确") String code,
                               @NotNull(message = "手机号不能为空") @Pattern(regexp = "^\\d{11}$", message = "手机号码不正确") String phone) {
        checkPhone(phone);
        UserEntity user = getUser();
        user.setPhone(phone);
        userService.updateUser(user);

        refreshAuthentication(request, response, generateNewAuthentication(user));

        return ReturnMsg.successTip();
    }

    // 刷新authentication和cookie
    private void refreshAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        if(checkCookie(request)){
            rememberMeService.loginSuccess(request, response, authentication);
        }
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    // 判断是否有remember-me的cookie,有才执行remember-me的后续
    private boolean checkCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if(cookies != null){
            for (Cookie cookie : cookies) {
                if("remember-me".equals(cookie.getName()))
                    return true;
            }
        }
        return false;
    }
}
  • 注入RememberMeServices(通过debug发现注入的其实就是PersistentTokenBasedRememberMeServices),RememberMeServices是springsecurity管理的,这里我们借用一下,特别注意这里一定要加上@Lazy注解,因为这个实例是security在构建的时候才创建的,不加会报错
@Bean
//@Lazy
public RememberMeServices rememberMeServices() throws Exception {
    return getHttp().getSharedObject(RememberMeServices.class);
}
  • 在controller中正常修改用户信息后,执行

rememberMeService.loginSuccess(request, response, authentication)

也就是创建新的cookie和持久化新的用户token,当session过期后也能根据新的cookie找到对应的用户信息实现自动登录

到这里其实已经能实现修改用户名后的后续自动登录了,但是你去看一下 persistent_logins(持久化token的表)会发现旧的token依旧存在表里。这是因为上面我们执行rememberMeService#loginSuccess这个方法不会删除旧的token,所以再完善一点的就是要写一个方法根据旧的用户名删除这个旧的token数据。

其实我也试过把注入的RememberMeServices强转为PersistentTokenBasedRememberMeServices,但是发现PersistentTokenBasedRememberMeServices不是注入的RememberMeServices的实例,debug发现是一个jdkProxy的代理类,后面就不去尝试了

你可能感兴趣的:(当springsecurity的remember-me功能遇上用户名修改)