spring cloud oauth2 替换用户信息

spring cloud oauth2 替换用户信息

在spring cloud 的oauth2认证中,有一个用户认证服务auth,提供客户端的认证,由于oauth2有多种授权方式,不同的授权采用的方式就不一样了。

在实际业务中,比如有个应用A,有自己的数据库A,需要auth授权后才能登陆,PC端登录的时候采用的是授权码模式,使用 @EnableOAuth2Sso 注解标记一个 WebSecurityConfigurerAdapter 类。当登录认证成功后会广播一个event事件,这个事件可以监听到,所以我们采用的是监听InteractiveAuthenticationSuccessEvent事件,这个是通过自动交互的手段来登录成功,比如cookie自动登录。具体实现细节如下,实际应用采用的是注释掉的代码,两种都可以参考:

   @EventListener
    public void authSuccessListener(InteractiveAuthenticationSuccessEvent event){
        System.out.println("哎呦喂,登录成功了");
        Authentication authentication=SecurityContextHolder.getContext().getAuthentication();
        //通用替换,针对用户名密码登录的
        if(authentication instanceof UsernamePasswordAuthenticationToken){
            UsernamePasswordAuthenticationToken originToken= (UsernamePasswordAuthenticationToken) authentication;
            String username= originToken.getName();
            System.out.println(username);
            //查找用户,这里直接模拟查到了用户,根据需求进行替换
            Person person=new Person(username,20);
            UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(originToken.getPrincipal(),"N/A",originToken.getAuthorities());
            token.setDetails(person);
            SecurityContextHolder.getContext().setAuthentication(token);
        }
        //auth2替换
        //替换oauth认证的信息里的details,这里就不展示了
       /* if (authentication instanceof OAuth2Authentication) {
            OAuth2Authentication originalOAuth2Authentication = (OAuth2Authentication) authentication;
            if (!originalOAuth2Authentication.isClientOnly()) {
                Authentication userAuthentication = originalOAuth2Authentication.getUserAuthentication();
                if (userAuthentication instanceof UsernamePasswordAuthenticationToken) {
                    UsernamePasswordAuthenticationToken originalUsernamePasswordAuthentication = (UsernamePasswordAuthenticationToken) userAuthentication;

                    String username = (String) originalUsernamePasswordAuthentication.getPrincipal();
                    //可以根据username查找用户,这里模拟获取用户
                    Person person=new Person("二狗子",18);
                    if (person != null) {
                        //替换用户信息,权限信息根据自己的需求替换,这里直接取原来的
                        UsernamePasswordAuthenticationToken usernamePasswordAuthentication = new UsernamePasswordAuthenticationToken(originalUsernamePasswordAuthentication.getPrincipal(), "N/A", originalUsernamePasswordAuthentication.getAuthorities());
                        usernamePasswordAuthentication.setDetails(person);

                        OAuth2Authentication oauth2Authentication = new OAuth2Authentication(originalOAuth2Authentication.getOAuth2Request(), usernamePasswordAuthentication);
                        oauth2Authentication.setDetails(originalOAuth2Authentication.getDetails());

                        SecurityContextHolder.getContext().setAuthentication(oauth2Authentication);
                    }
                }
            }
        }*/
    }

 

但是在APP登录的时候采用的授权方式是密码,这样认证的时候是根据认证token,只是一个token没有像pc端那样有cookie去自动验证,服务器是通过资源服务器认证的,只要token通过就可以访问被资源服务器保护的资源,这里都是/api/的接口。这种情况下就不能监听登录事件了,要在每次验证通过后去替换oauthAuthentication里面的details了,这样接口获取本应用当前登录用户的时候就可以直接获取了。那么如何实现认证成功后替换呢,根据spring security的尿性,增加一个filter,在最后一个filter之前替换。(注意:自定义过滤器交给spring托管可能出现doFilter被执行两次的问题,可以加个标记解决)

 

@Component
public class CustomerSecurityFilter extends GenericFilterBean {
    //加个标记,防止被执行两次
    //在spring容器托管的GenericFilterBean的bean,都会自动加入到servlet的filter chain,而我们还额外把filter加入到了spring security的
    //最后一个Filter之前。而spring security也是一系列的filter,在mvc的filter之前执行。因此在鉴权通过的情况下,就会先后各执行一次。
    private static final String FILTER_APPLIED = "__spring_security_customerFilter_filterApplied";
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if(servletRequest.getAttribute(FILTER_APPLIED)!=null){
           filterChain.doFilter(servletRequest,servletResponse);
           return;
        }
     
        System.out.println("哎呦呵,来啦");
        //替换用户信息,具体替换步骤参考上一个替换,这个用户最好存入缓存,毕竟过滤器过滤的请求挺多,每次都要查询很坑的
        servletRequest.setAttribute(FILTER_APPLIED,true);
        filterChain.doFilter(servletRequest,servletResponse);
    }
}
 @Autowired
    private CustomerSecurityFilter customerSecurityFilter;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/","/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/chat")
                .permitAll()
                .and()
                .logout()
                .permitAll()
                .and()
                .addFilterBefore(customerSecurityFilter,SwitchUserFilter.class);
    }

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/100307.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Linux 网络配置和管理

    Linux 网络配置和管理

  • sqlite开发图形界面_linux下sqlite3头文件

    sqlite开发图形界面_linux下sqlite3头文件哈哈,朋友编写了一款服务器web界面管理工具,使用到了SQLite数据库。SQLite介绍SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如Tcl…

  • Linux环境MySQL卸载教程「建议收藏」

    Linux环境MySQL卸载教程「建议收藏」Linux环境MySQL卸载

  • linux系统带界面,linux系统界面详情介绍[通俗易懂]

    linux系统带界面,linux系统界面详情介绍[通俗易懂]Linux作为一款免费的、开源的操作系统,linux系统界面也被广大开发者根据自身的喜好和审美设计的五花八门,有些Linux系统界面被开发者制作的相当精致,具有很强的观赏性和立体感,让人叹为观止,下面我们系统的介绍一下Linux系统界面。简单地说,Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的…

  • C语言中volatile关键字的使用

    C语言中volatile关键字的使用volatile是一个类型修饰符(typespecifier),就像我们熟悉的const一样,它是被设计用来修饰被不同线程访问和修改的变量;volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。作用编辑简单地说就是防止编译器对代码进行优…

  • vuex mapGetters的使用「建议收藏」

    vuex mapGetters的使用「建议收藏」importVuefrom’vue’;importVuexfrom’vuex’;Vue.use(Vuex);conststore=newVuex.Store({state:{name:’张三’,number:0,list:[{id:1,name:’111′},{id:2,name:’222′},{id:3,

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号