微服务开发基础框架学习与使用

在此感谢原作者的分享。https://blog.csdn.net/w1054993544/article/details/78932614

1.架构图

技术团队通过一段时间的积累后,我们打算对往后的一些新项目采用Spring Cloud技术栈来实现。大概微服务的架构如下:


微服务开发基础框架学习与使用_第1张图片
1.框架图.png

微服务开发基础框架学习与使用_第2张图片
2.项目工程结构图.png

微服务开发基础框架学习与使用_第3张图片
3操作流程图.png

2.Eureka服务注册与发现

•服务注册中心:服务的注册与发现。


微服务开发基础框架学习与使用_第4张图片
4.Euraka注册中心集群.png

微服务开发基础框架学习与使用_第5张图片
5.和doubble对比.png

微服务开发基础框架学习与使用_第6张图片
6.提供服务和注册服务.png

3.OAUTH2认证服务器

我这里采用Security-OAuth2.0 密码模式实现


微服务开发基础框架学习与使用_第7张图片
7.oauth2流程图.png

3.1 oauth2 server 配置

我采取了数据库和redis两种方式来存储token,可以方便切换,生成环境下建议使用redis方式。

3.1.1AuthorizationServerConfig

package com.microservice.skeleton.auth.config;

import com.microservice.skeleton.auth.error.MssWebResponseExceptionTranslator;
import com.microservice.skeleton.auth.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

import javax.sql.DataSource;

/**
 * Created by karp
 * Time:11:02
 * ProjectName:Mirco-Service-Skeleton
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;
    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    RedisTokenStore redisTokenStore(){
        return new RedisTokenStore(redisConnectionFactory);
    }

    //token存储数据库
//    @Bean
//    public JdbcTokenStore jdbcTokenStore(){
//        return new JdbcTokenStore(dataSource);
//    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetails());
    }
    @Bean
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }
    @Bean
    public WebResponseExceptionTranslator webResponseExceptionTranslator(){
        return new MssWebResponseExceptionTranslator();
    }
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
        endpoints.tokenStore(redisTokenStore())
                .userDetailsService(userDetailsService)
                .authenticationManager(authenticationManager);
        endpoints.tokenServices(defaultTokenServices());
        endpoints.exceptionTranslator(webResponseExceptionTranslator());//认证异常翻译
    }

    /**
     * 

注意,自定义TokenServices的时候,需要设置@Primary,否则报错,

* @return */ @Primary @Bean public DefaultTokenServices defaultTokenServices(){ DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setTokenStore(redisTokenStore()); tokenServices.setSupportRefreshToken(true); tokenServices.setClientDetailsService(clientDetails()); tokenServices.setAccessTokenValiditySeconds(60*60*12); // token有效期自定义设置,默认12小时 tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);//默认30天,这里修改 return tokenServices; } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.tokenKeyAccess("permitAll()"); security .checkTokenAccess("isAuthenticated()"); security.allowFormAuthenticationForClients(); } }

3.1.2WebSecurityConfig:

package com.microservice.skeleton.auth.config;

import com.microservice.skeleton.auth.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * Created by karp
 * Time:16:42
 * ProjectName:Mirco-Service-Skeleton
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsServiceImpl userDetailsService;

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

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().fullyAuthenticated()
                .antMatchers("/oauth/token").permitAll()
                .and()
                .csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**", "/plugins/**", "/favicon.ico");
    }

}

permitAll() 很关键:其中antMatchers("/oauth/token").permitAll() 给获取token请求授权。

3.2 UserDetailsServiceImpl实现

package com.microservice.skeleton.auth.service.impl;
import ch.qos.logback.core.net.SyslogOutputStream;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microservice.skeleton.auth.service.PermissionService;
import com.microservice.skeleton.auth.service.RoleService;
import com.microservice.skeleton.auth.service.UserService;
import com.microservice.skeleton.common.util.StatusCode;
import com.microservice.skeleton.common.vo.MenuVo;
import com.microservice.skeleton.common.vo.Result;
import com.microservice.skeleton.common.vo.RoleVo;
import com.microservice.skeleton.common.vo.UserVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by karp
 * Time:16:37
 * ProjectName:Mirco-Service-Skeleton
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Result userResult = userService.findByUsername(username);
        if (userResult.getCode() != StatusCode.SUCCESS_CODE) {
            throw new UsernameNotFoundException("用户:" + username + ",不存在!");
        }
        Set grantedAuthorities = new HashSet<>();
        boolean enabled = true; // 可用性 :true:可用 false:不可用
        boolean accountNonExpired = true; // 过期性 :true:没过期 false:过期
        boolean credentialsNonExpired = true; // 有效性 :true:凭证有效 false:凭证无效
        boolean accountNonLocked = true; // 锁定性 :true:未锁定 false:已锁定
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(userResult.getData(),userVo);
        Result> roleResult = roleService.getRoleByUserId(userVo.getId());
        if (roleResult.getCode() == StatusCode.SUCCESS_CODE){
            List roleVoList = roleResult.getData();
            for (RoleVo role:roleVoList){
                //角色必须是ROLE_开头,可以在数据库中设置
                GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_"+role.getValue());
                System.out.println("grantedAuthority---角色------->ROLE_"+role.getValue());
                grantedAuthorities.add(grantedAuthority);
                //获取权限
                Result> perResult  = permissionService.getRolePermission(role.getId());
                if (perResult.getCode() == StatusCode.SUCCESS_CODE){
                    List permissionList = perResult.getData();
                    for (MenuVo menu:permissionList
                            ) {
                        GrantedAuthority authority = new SimpleGrantedAuthority(menu.getUrl());
                        grantedAuthorities.add(authority);
                        System.out.println("grantedAuthority---菜单------->"+menu.getUrl());
                    }
                }
            }
        }
        User user = new User(userVo.getUsername(), userVo.getPassword(),
                enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuthorities);
        return user;
    }
}

3.3 mss-oauth yml文件配置

server:
  port: 9060

spring:
  application:
    name: authcenter
  jpa:
    show-sql: true
  datasource:
    url: jdbc:mysql://localhost:4306/nsinformation?useUnicode=true&characterEncoding=utf-8
    username: nsinformation
    password: ***
    druid:
      driver-class-name: com.mysql.jdbc.Driver
  redis:
    host: ***
    port: 6489
    password: ***
eureka:
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    ##续约更新时间间隔设置5秒,m默认30s
    lease-renewal-interval-in-seconds: 1
    ##续约到期时间10秒,默认是90秒
    lease-expiration-duration-in-seconds: 2
  client:
      service-url:
        defaultZone: http://mss-eureka:9010/eureka/ #目前是单节点,多节点可以在后面追加
logging:
  config: classpath:logback.xml
  level:
    org:
      springframework:
        web: info
###feign 默认关闭熔断,请看HystrixFeignConfiguration
feign:
  hystrix:
    enabled: false
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000
ribbon:
  ReadTimeout: 30000
  ConnectTimeout: 60000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1
  ActiveConnectionsLimit: 2147483647

4.mss-config配置中心

4.1配置中心serve端

server.port = 8001
server.tomcat.uri-encoding = UTF-8

spring.application.name=configServer
spring.profiles.active=subversion
spring.cloud.config.server.svn.uri=http://***:1080/AgriculturalWaterInformatization/trunk/Micro-Service-Skeleton/configfiletest/
spring.cloud.config.server.svn.username=***
spring.cloud.config.server.svn.password=***
spring.cloud.config.server.default-label={application}
spring.cloud.config.enabled=true

4.2配置中心客户端

微服务开发基础框架学习与使用_第8张图片
8.image.png

5.Zuul网关(mss-gateway)

5.1开启支持Sso

@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
    }
}

5.2配置文件

网关把/uaa/**请求都转发到oauth2.0中心,oauth2.0中心对所有的请求需要认证授权,如果不需要授权,那么在WebSecurityConfig设置permitall就可以了。

spring:
  application:
    name: mss-gateway
server:
  port: 9030
eureka:
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    lease-renewal-interval-in-seconds: 1 # 心跳检测检测与续约时间
    lease-expiration-duration-in-seconds: 2 # 测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服
  client:
      service-url:
        defaultZone: http://mss-eureka:9010/eureka/
zuul:
  host:
    connect-timeout-millis: 10000
    socket-timeout-millis: 60000
  routes:
    uaa:
      path: /uaa/**
      strip-prefix: true
      sensitiveHeaders:
      serviceId: authcenter
    upms:
      path: /upms/**
      strip-prefix: true
      sensitiveHeaders:
      serviceId: mss-upms
management:
  security:
    enabled: false
security:
  oauth2:
    client:
      access-token-uri: http://localhost:9030/uaa/oauth/token #网关的地址
      user-authorization-uri: http://localhost:9030/uaa/oauth/authorize
    resource:
      user-info-uri: http://localhost:9060/user #安全策略里获取用户信息。
      prefer-token-info: false

#    resource:
#      user-info-uri:  http://localhost:9060/upms/user
#      prefer-token-info: false
##############end#####################
####超时配置####
ribbon:
  ReadTimeout: 20000
  ConnectTimeout: 20000
  MaxAutoRetries: 1
  MaxAutoRetriesNextServer: 2
  ActiveConnectionsLimit: 2147483647
  eureka:
    enabled: true
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 600000
###超时配置###

6.mss-transaction 消息总线

这里采用rabbitmq来实现,配置文件如下:


server:
  port: 9070
spring:
  application:
    name: mss-transaction
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://***:4306/nsinformation?useUnicode=true&characterEncoding=utf-8
    username: nsinformation
    password: ***
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    publisher-confirms: true
    virtual-host: /
eureka:
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    ##续约更新时间间隔设置5秒,m默认30s
    lease-renewal-interval-in-seconds: 1
    ##续约到期时间10秒,默认是90秒
    lease-expiration-duration-in-seconds: 2
  client:
      service-url:
        defaultZone: http://mss-eureka:9010/eureka/

7.展示

7.1分别启动

register、auth-center、mss-gateway、mss-upms


微服务开发基础框架学习与使用_第9张图片
7.1启动图页.png

微服务开发基础框架学习与使用_第10张图片
7.1.1eureka界面图.png

7.2获取token

http://localhost:9030/uaa/oauth/token

用postman 设置basic Auth(可在数据库oauth_client_details表中设置)
请求参数为:
grant_type:password
username:admin
password:123456
image.png

微服务开发基础框架学习与使用_第11张图片
image.png

微服务开发基础框架学习与使用_第12张图片
image.png

7.3刷新token

微服务开发基础框架学习与使用_第13张图片
image.png

7.4获取资源(调用其他接口)

http://localhost:9030/upms/user/test**](http://localhost:9030/upms/user/test)
注意:****heard****头部添加:****Authorization 值:bearer +token

微服务开发基础框架学习与使用_第14张图片
image.png

总结

由于刚开始学习spring cloud以及对spring security不太了解,对oauth2.0规范也进行了查缺补漏,基本框架已经搭建完毕。
源码地址
源码地址
源码地址

你可能感兴趣的:(微服务开发基础框架学习与使用)