在其他模块中使用springsession与springsecurity获取当前登录用户

目录

  • 下面主要介绍如何在其他模块中获取当前用户
    • 1. 添加依赖
    • 2. 进行session及redis的配置
    • 3. 进行springsecurity配置
    • 4. 获取当前用户
    • 5. 错误调试
    • 6. 关于每次都要创建相同包和对象的解决方案
      • 1. **将用户管理放到一个共通的模块中,然后打成一个jar包,在新的模块中直接引入此包进行使用。**
      • 2. 序列化有可以忽略包路径的方式,具体方法我也忘记了。可以自行查找。

在分布式的系统中,我们会将整个系统划分为多个模块,但是这些模块中会有一些共通的地方,如当前登录用户。为了方便管理当前登录的用户,通常会将用户信息保存到redis中。

在此前的文章中,使用springsession与springsecurity结合实现redis进行用户session的管理。具体实现可见,springsecurity/springboot中使用spring-security进行登陆控制&&springsession/springSession+springSecurity结合使用实现redis管理session.md

下面主要介绍如何在其他模块中获取当前用户

1. 添加依赖


    org.springframework.session
    spring-session-data-redis
    ${spring.boot.version}


            org.springframework.boot
            spring-boot-starter-security
        

2. 进行session及redis的配置

@Configuration
@EnableRedisHttpSession
public class SessionConfig {

    @Value("${jetcache.remote.default.host}")
    private String redisHost;

    @Value("${jetcache.remote.default.port}")
    private int redisPort;

    @Value("${jetcache.remote.default.password}")
    private String redisPwd;

    @Bean
    public JedisConnectionFactory connectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(redisHost);
        redisStandaloneConfiguration.setDatabase(0);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(redisPwd));
        redisStandaloneConfiguration.setPort(redisPort);

        return new JedisConnectionFactory(redisStandaloneConfiguration);
    }
}
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
    public SecurityInitializer() {
        super(SessionConfig.class, Config.class);
    }
}

3. 进行springsecurity配置

这里只是为了允许我进行测试接口的访问,所以简单允许所有请求访问:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers(HttpMethod.GET).permitAll()
                .antMatchers(HttpMethod.POST).permitAll()
                .antMatchers("/api/**").permitAll();
        http.csrf().disable();
    }
}

4. 获取当前用户

@Service("userServiceImpl")
@Slf4j
public class UserServiceImpl implements IUserService {
    @Override
    public void getCurrentUser() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        Object myUser = (auth != null) ? auth.getPrincipal() : null;

        System.Out.Print(myUser);
    }
}

或许看到这里,会很奇怪这和之前的文章中获取redis用户有什么不同的?接下来的一番错误会让你明白有什么不同之处。

5. 错误调试

按照我原先的理解,这个时候我在controller层调用此service就会在控制台打印用户的详细信息,但是现实并没有想象中的那么美好。报了如下错误:

Failed to deserialize payload...

ClassNotFound: com.mas.leadsscoring.process.vo.UserVO.java

这个对象就是在集合springsecurity框架时候实现UserDetail接口的实体类,但是在此模块中我并没有创建此对象,因为我还没有用到此对象。没用到为什么就开始报错了呢?

原来是UserDetail实现了Serializable接口,在springsession将securtyContext对象保存到redis 的时候会将此对象序列化,而现在我们从redis获取信息的时候需要再将其反序列化成原来的对象,但是现在这些包路径和对象在新的模块中是无法找到的,所以会报此错误。

在其他模块中使用springsession与springsecurity获取当前登录用户_第1张图片

将userVo对象在新的模块包中新建(可能会有人有疑问,那岂不是每个模块中都要新建此包路径吗,那不是很麻烦,下面会提到解决方案):

@Data
public class UserVO implements UserDetails {

    /**
     * 用户ID
     */
    private String userId;

    /**
     * 用户账号
     */
    private String user;

    /**
     * 用户名
     */
    private String userName;

    /**
     * 密码
     */
    private String password;

    /**
     * 是否为回收站,0表示不是,1表示是
     */
    private String isRecycle;

    /**
     * 是否可用。Y表示可用,N表示不可用
     */
    private String isEnable;

    /**
     * 创建人
     */
    private String createBy;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新人
     */
    private String updateBy;

    /**
     * 更新时间
     */
    private Date updateTime;

    /**
     * 备注
     */
    private String comment;

    /**
     * 用户角色
     **/
    private List roles;


    @Override
    public Collection getAuthorities() {
        List authorities = new ArrayList<>();
        for (TtRole role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getRole()));
        }
        return authorities;
    }

    @Override
    public String getUsername() {
        return userName;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {

        return "y".equals(isEnable)  ;
    }

}

加上此类后又报TtRole类找不到,这是因为UserVo对象中引用了TtRole。同样的,在指定包目录下新建ttrole对象。

这时候再测试获取当前用户已经ok。

6. 关于每次都要创建相同包和对象的解决方案

1. 将用户管理放到一个共通的模块中,然后打成一个jar包,在新的模块中直接引入此包进行使用。

2. 序列化有可以忽略包路径的方式,具体方法我也忘记了。可以自行查找。

你可能感兴趣的:(springboot,springsession,springsecurity)