SpringSecurity OAtu2+JWT实现微服务版本的单点登录的示例

 更新时间:2022年05月24日 08:45:54   作者:梵高的猪v  
本文主要介绍了SpringSecurity OAtu2+JWT实现微服务版本的单点登录的示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

何为单点登录

单点登录通俗的话来讲在微服务当中,在一个服务登录后就能免去另一个服务的登录操作,所谓单点登录.

就好像你在微博总网站里登录后,然后在微博里面的某一个模块点进去后,就发现这个模块竟然不用登录了,不是因为这个模块与主网站是一体的用一个SpringSecurity就可以搞定了,这里面的水深着呢!
感兴趣更深这个SpringSecurity建议去看看图灵课堂的SpringSecurity,建议不要看尚硅谷的,那个版本说实话感觉有点老式了,教你手写,其实我觉得,你既然学到了这个层次了,就应该能建立起快速打通一个新技术的能力,这个"打通"的意思不是要你深入,而是会用!别想着深入,因为没有什么实际意义,现在不是我们小白应该做的事,我们小白只要打好基础就可以了,比如java,jvm,spring,mysql这些!
没有SpringSecurity基础就别看这篇文章了,你可能看得懂,但是你肯定实现不出来,不信我你就看

认证中心

新建一个微服务模块,可以另外建项目,也可以直接在你微服务项目里建立模块就可以了.

maven配置

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

用户登录逻辑

@Component
public class SheepUserDetailsService implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        if( !"admin".equals(s) )
            throw new UsernameNotFoundException("用户" + s + "不存在" );

        return new User( s, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_NORMAL,ROLE_MEDIUM"));
    }
}

OAtuh2配置

配置服务中心

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    SheepUserDetailsService sheepUserDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        // 定义了两个客户端应用的通行证
        clients.inMemory()
                .withClient("admin")
                .secret(new BCryptPasswordEncoder().encode("123456"))
                .authorizedGrantTypes("authorization_code", "refresh_token","password")
                .scopes("all")
                .autoApprove(true)
                .redirectUris("http://192.168.216.1:8001/login","http://192.168.216.1:8004/login");

    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter());
        DefaultTokenServices tokenServices = (DefaultTokenServices) endpoints.getDefaultAuthorizationServerTokenServices();
        tokenServices.setTokenStore(endpoints.getTokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(1)); // 一天有效期
        endpoints.tokenServices(tokenServices);

        //密码模式配置
        endpoints.authenticationManager(authenticationManager).userDetailsService(sheepUserDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                .tokenKeyAccess("isAuthenticated()")
                .checkTokenAccess("permitAll()")
                .allowFormAuthenticationForClients();
    }

    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("testKey");
        return converter;
    }

}

配置规则中心

Configuration

public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {


    @Override
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Autowired
    private CustomLogoutSuccessHandler customLogoutSuccessHandler;


    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        authenticationProvider.setHideUserNotFoundExceptions(false);
        return authenticationProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**","/uac/oauth/token","/remove")
                .and()
                .authorizeRequests()
                .antMatchers("/oauth/**").authenticated()
                .and()
                .formLogin().permitAll()
                .and()
                .logout()
                .logoutSuccessHandler(customLogoutSuccessHandler)
                // 无效会话
                .invalidateHttpSession(true)
                // 清除身份验证
                .clearAuthentication(true)
                .permitAll();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

}
@Component
public class CustomLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        // 将子系统的cookie删掉
        //建议将token也删除,直接写个controller接口就可以了,可以在前端调用/logout的同时调用删除token接口
        Cookie[] cookies = request.getCookies();
        if(cookies != null && cookies.length>0){
            for (Cookie cookie : cookies){
                cookie.setMaxAge(0);
                cookie.setPath("/");
                response.addCookie(cookie);
            }
        }
        super.handle(request, response, authentication);
    }
}

请求模块

下面这个是请求模块,也就是独立出一个微服务,假如这个微服务是做业务的,会给认证中心发出请求,然后去热证,这个模块也算登录了.
那么有道友会问:其他模块在该模块登录后还要登录吗?答案:不用!
至于要以什么为基础,接着往下看:

请求模块这个依赖很关键

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>

这个yml也很重要

auth-server: http://localhost:8085/uac
security:
  oauth2:
    client:
      client-id: admin
      client-secret: 123456
      user-authorization-uri: ${auth-server}/oauth/authorize #认证
      access-token-uri: ${auth-server}/oauth/token #获取token
    resource:
      jwt:
        key-uri: ${auth-server}/oauth/token_key #忘了,反正要写上

上面的认证和获取token这两个配置很重要,还有一个/oauth/check_token,这个是用来检查token是否合法的,这些都怎么用,是什么,后面会说

下面这个也很重要

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableOAuth2Sso
public class ClientWebsecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
    //下面表示该模块所有请求都要拦截
    //因为在yml配置了认证中心的各个路径,所以会自动跳转到认证中心去认证
    //如果你想在当前模块排除哪些拦截,可以在下面去排除
        http.antMatcher("/**").authorizeRequests()
                .anyRequest().authenticated();
    }
}

真实请求

下面就可以正式去请求了,这里很多网友都会有疑问,就是前面我在认证中心授予了权限之后,在其他模块该如何去权限的规定呢?其实很简单,有很多博主都没有说,直接加上注解就可以了.

    @GetMapping("/get")
    @PreAuthorize("hasAuthority('ROLE_NORMAL')")
    public String get(HttpServletRequest request){
        System.out.println("函数进来了");
        return "uusb1j";
    }
}

这个时候,如果该微服务的get请求过来,就会跳转到认证中心去认证.

一些小问题

这个时候只要有相同配置的模块都不用自行登录了.如果有一个模块进行登出请求,所有服务都会进行登出.

注意认证中心有项配置redirectUris(“http://192.168.216.1:8001/login”,“http://192.168.216.1:8004/login”),这个配置代表认证成功后重定向去哪个地址,但并不会真的重定向去对应模块的login页,而是重定向去你请求前被拦截的地址,但是这个有讲究就是必须配置请求前所在模块的地址,每个模块对应一个重定向地址,最好是重定向到对应模块的/login页,其他页也行.如果你从网关过来,然后你这里重定向回网关是不行的,除非你网关有相关操作,不然你网关只是一个转发功能,是先转发到对应模块,然后发现该模块的某个地址不可访问,才去认证中心请求权限的,所以这里的重定向地址还是具体到对应模块才对,其他不行,有多个用","隔开就行.

到此这篇关于SpringSecurity OAtu2+JWT实现微服务版本的单点登录的示例的文章就介绍到这了,更多相关SpringSecurity OAtu2 JWT单点登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JAVA使用POI获取Excel的列数与行数

    JAVA使用POI获取Excel的列数与行数

    Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。 下面这篇文章给大家介绍了JAVA使用POI获取Excel列数和行数的方法,有需要的朋友们可以参考借鉴,下面来一起看看吧。
    2016-12-12
  • JAVA实现微信APPV3支付保姆级教程

    JAVA实现微信APPV3支付保姆级教程

    微信实现支付功能与支付宝实现支付功能是相似的,这篇文章主要介绍了JAVA实现微信APPV3支付的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • 基于ssm中dao接口@Param注解的用法

    基于ssm中dao接口@Param注解的用法

    这篇文章主要介绍了基于ssm中dao接口@Param注解的用法,具有很好的参考价值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • SpringBoot使用JSch操作Linux的方法

    SpringBoot使用JSch操作Linux的方法

    JSch是一个Java库,它提供了SSH(Secure Shell)的Java实现,允许Java程序通过SSH协议连接到远程系统(如Linux),这篇文章主要介绍了SpringBoot使用JSch操作Linux,需要的朋友可以参考下
    2023-11-11
  • 解决json字符串序列化后的顺序问题

    解决json字符串序列化后的顺序问题

    这篇文章主要介绍了解决json字符串序列化后的顺序问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • Thymeleaf对象的使用之基本对象实例解析

    Thymeleaf对象的使用之基本对象实例解析

    这篇文章主要介绍了Thymeleaf对象的使用之基本对象实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Java中IO流 RandomAccessFile类实例详解

    Java中IO流 RandomAccessFile类实例详解

    这篇文章主要介绍了Java中IO流 RandomAccessFile类实例详解的相关资料,需要的朋友可以参考下
    2017-05-05
  • Spring ComponentScan的扫描过程解析

    Spring ComponentScan的扫描过程解析

    这篇文章主要介绍了spring ComponentScan的扫描过程解析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • Java实现员工管理系统

    Java实现员工管理系统

    这篇文章主要为大家详细介绍了Java实现员工管理系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • java提高篇(二三)-----HashMap详解

    java提高篇(二三)-----HashMap详解

    HashMap基于哈希表的 Map 接口的实现,本篇文章主要讲诉了java中HashMap,有兴趣的可以了解一下。
    2016-11-11

最新评论