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);
    }

 

 

 

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • anaconda与pycharm的关系、安装「建议收藏」

    anaconda与pycharm的关系、安装「建议收藏」一、anaconda和pycharm的关系anaconda和miniconda的介绍Anaconda:是一个打包的集合,它里面预装好了conda、某个版本的python、众多packages、科学计算工具等等,就是把很多常用的不常用的库都给你装好了,并且在安装一个库时会询问是否安装与该库相关联的库,它将库之间的关系理的非常清楚,为用户提供极大的便利。Miniconda,顾名思义,它只包含最基本的内容——python与conda,以及相关的必须依赖项,对于空间要求严格的用户,Miniconda是一种

    2022年8月25日
    4
  • Struts2的通配符配置方式[通俗易懂]

    Struts2的通配符配置方式[通俗易懂]Struts2的Action类很有意思,你可以使用3种方式来实现具体的Action类:以上三种Action的实现方式都可以被struts2框架自动识别,如果你在struts.xml里面配置了一个ac

    2022年7月1日
    21
  • vim撤销、回退操作「建议收藏」

    vim撤销、回退操作「建议收藏」打个广告,请有意向加入腾讯的前端,将简历发送至mzxbupt@gmail.com在vi中按u可以撤销一次操作u  撤销上一步的操作Ctrl+r恢复上一步被撤销的操作注意:如果你输入“u”两次,你的文本恢复原样,那应该是你的Vim被配置在Vi兼容模式了。重做如果你撤销得太多,你可以输入CTRL-R(redo)回退前一个命令。换句话说,它撤销一个撤销。要看执行的…

    2022年6月16日
    407
  • Protostuff序列化和反序列化使用说明

    Protostuff序列化和反序列化使用说明google原生的protobuffer使用起来相当麻烦,首先要写.proto文件,然后编译.proto文件,生成对应的.java文件,鄙人试了一次,发现真的很麻烦。而protostuff的官方网站(http://www.protostuff.io/documentation/runtime-schema/),对于智商比较低的小编来说也略显生涩,于是鄙人就根据项目中用到的protostuff,撰写此文,以方便自己和他人加深印象和学习。

    2022年6月17日
    33
  • 学习大数据需要掌握哪些Java技术

    学习大数据需要掌握哪些Java技术大数据产业已进入发展的”快车道”,急需大量优秀的大数据人才作为后盾。如果你是Java编程出身,那学习大数据自然是锦上添花;但如果你是刚刚接触大数据技术,还在Java编程基础阶段,这篇文章非常值得你看!首先,我们学习大数据,为什么要先掌握Java技术?Java是目前使用非常广泛的编程语言,它具有的众多特性,特别适合作为大数据应用的开发语言。Java不仅吸收了C++语言的各种优点…

    2022年5月12日
    58
  • main方法的各种书写样式

    main方法的各种书写样式以下是一些正确的和一个错误的:publicstaticvoidmain(String[]args)publicstaticfinalvoidmain(String[]args)staticpublicvoidmain(String[]args)staticpublicsynchronizedvoidmain(String[]args)staticpublicabstractvoidmain(String[]args)//错误,abstract要求没

    2022年5月31日
    36

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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