栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot实践(二十九):oauth2+security+gateway的登录实现

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot实践(二十九):oauth2+security+gateway的登录实现

前面介绍单体的security使用,SpringBoot实践(二十六):Security实现Vue-Element-Admin登录拦截(适合单体应用)_A叶子叶的博客-CSDN博客微服务与单体不同在于所有服务都要过网关,若使用gateway则更要考虑异构问题(security是基于MVC的,而gateway是基于webFlux的),因此在实现上把登录/授权相关功能放在同个工程,而token校验要放在网关中(依然使用security),结合oauth2实现授权模式。假设使用security框架的登录/授权工程叫login,在gateway进行token的拦截后回调login工程中的token校验接口,也就是说进行功能拆分,本文提供一种参考实现。

login工程的security配置
userDetailsService是必须重写用于用户的校验,其他不配置。
@Configuration
@EnableWebSecurity
@AllArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests().antMatchers("/oauth
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    @Bean
    public PasswordEncoder passwordEncoder()  {
        return new BCryptPasswordEncoder();
    }
}
login工程的oauth2配置

使用oauth2的token增强,重写clientDetailsService实现password授权模式;

@AllArgsConstructor
@Configuration
@EnableAuthorizationServer
public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private  AuthenticationManager authenticationManager;
    @Autowired
    private  ClientDetailsServiceImpl clientDetailsService;
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        
        clients.withClientDetails(clientDetailsService);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List delegates = new ArrayList<>();
        delegates.add(tokenEnhancer());
        delegates.add(accessTokenConverter());
        enhancerChain.setTokenEnhancers(delegates); //配置JWT的内容增强器
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService) //配置加载用户信息的服务
                .accessTokenConverter(accessTokenConverter())
                .tokenEnhancer(enhancerChain);

    }

    
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
    }


    
    @Bean
    public TokenEnhancer tokenEnhancer() {
        TokenEnhancer tokenEnhancer = (accessToken, authentication) -> {
            Map additionalInfo = new HashMap<>();
            Object principal = authentication.getUserAuthentication().getPrincipal();
            if (principal instanceof SecurityUser) {
                SecurityUser sysUserDetails = (SecurityUser) principal;
                additionalInfo.put("userId", sysUserDetails.getId());
            }
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            return accessToken;
        };
        return tokenEnhancer;
    }


    
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setKeyPair(keyPair());
        return jwtAccessTokenConverter;
    }
    
    @Bean
    public KeyPair keyPair() {
        //从classpath下的证书中获取秘钥对
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray());
        return keyStoreKeyFactory.getKeyPair("jwt", "123456".toCharArray());
    }

}
网关的授权模式

gateway只进行token的拦截,通过即放行。


@AllArgsConstructor
@Configuration
@EnableWebFluxSecurity
public class ResourceServerConfig {
    private final ResourceServerManager         resourceServerManager;
    private final WhiteListConfig             whiteListConfig;
    private final RequestAccessDeniedHandler restfulAccessDeniedHandler;
    private final RequestAuthenticationEntryPoint restAuthenticationEntryPoint;
    private final IgnoreUrlsRemoveJwtFilter ignoreUrlsRemoveJwtFilter;

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
                .oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(jwtAuthenticationConverter());
                //.jwkSetUri()  // 远程获取公钥,默认读取的key是spring.security.oauth2.resourceserver.jwt.jwk-set-uri

        //自定义处理JWT请求头过期或签名错误的结果
        http.oauth2ResourceServer().authenticationEntryPoint(restAuthenticationEntryPoint);

        //对白名单路径,直接移除JWT请求头
        http.addFilterBefore(ignoreUrlsRemoveJwtFilter, SecurityWebFiltersOrder.AUTHENTICATION);


        http.authorizeExchange()
                //白名单配置
                .pathMatchers(whiteListConfig.getUrls().stream().toArray(String[]::new)).permitAll()
                //鉴权管理器配置
                .anyExchange()
                .access(resourceServerManager)
                .and()
                .exceptionHandling()
                //处理未授权
                .accessDeniedHandler(restfulAccessDeniedHandler)
                //处理未认证
                .authenticationEntryPoint(restAuthenticationEntryPoint)
                .and()
                .csrf().disable();

        return http.build();
    }

    
    @Bean
    public Converter> jwtAuthenticationConverter()
    {
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix(SecurityConstants.AUTHORITY_PREFIX);
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(SecurityConstants.JWT_AUTHORITIES_KEY);
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
    }
}

综上,微服务架构实现的功能拆分是网关只当做授权客户端,login模块所有的登录/授权功能,假如不适用oauth2,也可以根据之前的单体security设置+自定义的网关拦截验证完成password模式。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1040003.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号