基于spring cloud的oauth2+redis+swgger2的认证权限工程

一、微服务跨域访问cors设置

     注意,只要网管zuul设置就可以了,如果底下的服务配置和网关都设置,导致跨域失败。

     这种跨域问题,经常出现在前后端分离。

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许cookies跨域
        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

二、集成构建restful API的swagger2

引入pom


            io.springfox
            springfox-swagger-ui
            ${swagger.version}
        

        
            io.springfox
            springfox-swagger2
            ${swagger.version}

基于spring cloud的oauth2+redis+swgger2的认证权限工程_第1张图片

三、OAuth2搭建

    1.添加依赖

 
            org.springframework.cloud
            spring-cloud-starter-security
        
        
            org.springframework.cloud
            spring-cloud-starter-oauth2
 

    2.增加oauth2配置类,和启用注解(资源服务区和授权服务器)

配置授权服务器,实现一个授权服务,需要授权类型(grantType),不同授权类型视为不同的客户端,提供不同的获取令牌(Token)的方式,每一个客户端都可以通过明确的配置以及权限来实现不同的授权访问机制。

配置类中,需要重写几个方法,来配置授权服务器

客户端的详情,clientDetails

ClientDetailsServiceConfigurer可以用内存或JDBC方式实现获取已注册的客户端详情。

clientId:客户端标识ID

secret:客户端安全码

scope:客户端访问范围,默认为空则拥有全部范围

authorizedGrantTypes:客户端使用的授权类型,默认为空

authorities:客户端可使用的权限

    /**
     * 我们将client信息存储到oauth_client_details表里
* 并将数据缓存到redis * * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.withClientDetails(redisClientDetailsService); redisClientDetailsService.loadAllClientToCache(); }

ClientDetailsServiceConfigurer:配置客户端详细服务(ClientDetailsService)。客户端的相信信息在这里初始化(访问者的信息)。这里可以写死,可以从数据库。我们是通过redis缓存,可以增加时效性。

这个需要按官方给的表结构在数据库构建,来保存客户端信息,设置你自己的账号,密码

后面获得token权限访问需要加账号

http://localhost:8771/auth/oauth/token?username=wangxi&password=111111&grant_type=password&scope=app&client_id=system&client_secret=111111

   我们自定义redisClientDetailsService,继承JdbcClientDetailsService。

    对于redisClientDetailsService,需要重写几个方法,这些方法都是对于客户端详细信息的处理。

需要将客户端详细信息存在数据库 和 redis

@Autowired
    private StringRedisTemplate stringRedisTemplate;

    //配置数据源
    public RedisClientDetailsService(DataSource dataSource) {
        super(dataSource);
    }
 @Override
    public ClientDetails loadClientByClientId(String clientId) throws InvalidClientException {
        ClientDetails clientDetails = null;

        // 先从redis获取
        String value = (String) stringRedisTemplate.boundHashOps(CACHE_CLIENT_KEY).get(clientId);
        if (StringUtils.isBlank(value)) {
            clientDetails = cacheAndGetClient(clientId);
        } else {
            clientDetails = JSONObject.parseObject(value, BaseClientDetails.class);
        }

        return clientDetails;
    }



 /**
     * 缓存client并返回client
     *
     * @param clientId
     */
    private ClientDetails cacheAndGetClient(String clientId) {
        // 从数据库读取
        ClientDetails clientDetails = super.loadClientByClientId(clientId);
        if (clientDetails != null) {// 写入redis缓存
            stringRedisTemplate.boundHashOps(CACHE_CLIENT_KEY).put(clientId, JSONObject.toJSONString(clientDetails));
        }

        return clientDetails;
    }

父类提供了从数据库取客户端信息公共方法,我们会需要增加的就是写入redis

还有@Override
    public void updateClientDetails(ClientDetails clientDetails) throws NoSuchClientException

以及@Override
    public void updateClientDetails(ClientDetails clientDetails) throws NoSuchClientException

@Override
    public void removeClientDetails(String clientId) throws NoSuchClientException

这些方法从字面理解就可以了。我们这里要做的就是同步更新redis即可。

 

AuthorizationServerEndpointsConfigurer:用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)。

authenticationManager:认证管理器,当你选择了资源所有者的密码授权类型,需要设置这个属性注入一个authenticationManager对象

userDetailsService:定义自己的userDetailsService验证用户

authorizationCodeServices:设置收取码服务,AuthorizationCodeServices 的实例。用于authorization_code授权码类型

对象有一个 pathMapping() 方法用来配置端点的 URL

下面是一些默认的端点 URL:

  • /oauth/authorize:授权端点
  • /oauth/token:令牌端点
  • /oauth/confirm_access:用户确认授权提交端点
  • /oauth/error:授权服务错误信息端点
  • /oauth/check_token:用于资源服务访问的令牌解析端点
  • /oauth/token_key:提供公有密匙的端点,如果你使用JWT令牌的话
@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    //默认的认证管理器
        endpoints.authenticationManager(this.authenticationManager);
    //设置令牌,生成token方式和存储
        endpoints.tokenStore(tokenStore());
    //redis存储授权码,就是将授权码,存在redis中
        endpoints.authorizationCodeServices(redisAuthorizationCodeServices);
        if (storeWithJwt) {
            endpoints.accessTokenConverter(accessTokenConverter());
        } else {
            endpoints.tokenEnhancer((accessToken, authentication) -> {
                addLoginUserInfo(accessToken, authentication);
                return accessToken;
            });
        }
    }


 /**
     * 令牌存储
     */
    @Bean
    public TokenStore tokenStore() {
    //配置文件,设置是否用jwt生成token,并存入数据库
    //对于jwt,我们需要转换器来自定义
        if (storeWithJwt) {
            return new JwtTokenStore(accessTokenConverter());
        }
    //使用Redis来存令牌,下面的RandomAuthenticationKeyGenerator,则是生成一个uuid唯一字符,set到redis中
        RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
        redisTokenStore.setAuthenticationKeyGenerator(new RandomAuthenticationKeyGenerator());

        return redisTokenStore;
    }

  /**
     * Jwt资源令牌转换器
只是扩展可以不看 * 参数access_token.store-jwt为true时用到 * * @return accessTokenConverter */ @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter() { @Override public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { OAuth2AccessToken oAuth2AccessToken = super.enhance(accessToken, authentication); addLoginUserInfo(oAuth2AccessToken, authentication); // 2018.07.13 将当前用户信息追加到登陆后返回数据里 return oAuth2AccessToken; } }; DefaultAccessTokenConverter defaultAccessTokenConverter = (DefaultAccessTokenConverter) jwtAccessTokenConverter .getAccessTokenConverter(); DefaultUserAuthenticationConverter userAuthenticationConverter = new DefaultUserAuthenticationConverter(); userAuthenticationConverter.setUserDetailsService(userDetailsService); defaultAccessTokenConverter.setUserTokenConverter(userAuthenticationConverter); jwtAccessTokenConverter.setSigningKey(signingKey); return jwtAccessTokenConverter; }

AuthorizationServerSecurityConfigurer:用来配置令牌端点(Token Endpoint)的安全约束

 @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients(); // 允许表单形式的认证
    }
   /**
     * 我们将client信息存储到oauth_client_details表里
* 并将数据缓存到redis * * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.withClientDetails(redisClientDetailsService); redisClientDetailsService.loadAllClientToCache(); }

 

资源服务器:resource-server

要访问资源服务器受保护的资源需要携带令牌(授权服务器获得)

客户端之前也是资源服务器,各个服务相互访问需要携带令牌。

基于spring cloud的oauth2+redis+swgger2的认证权限工程_第2张图片

  • tokenServices:ResourceServerTokenServices 类的实例,用来实现令牌业务逻辑服务
  • resourceId:这个资源服务的ID,这个属性是可选的,但是推荐设置并在授权服务中进行验证
  • tokenExtractor 令牌提取器用来提取请求中的令牌
  • 请求匹配器,用来设置需要进行保护的资源路径,默认的情况下是受保护资源服务的全部路径
  • 受保护资源的访问规则,默认的规则是简单的身份验证(plain authenticated)
  • 其他的自定义权限保护规则通过 HttpSecurity 来进行配置

注意:认证中心,我们编写

基于spring cloud的oauth2+redis+swgger2的认证权限工程_第3张图片

其他服务端,我们访问认证中心,只要返回用户信息 不是null则认为认证成功

基于spring cloud的oauth2+redis+swgger2的认证权限工程_第4张图片

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(spring,cloud)