SpringCloud--zuul和oauth2
阿新 • • 發佈:2019-01-05
文章目錄
此篇我將介紹 將zuul 層 和 oauth2 進行分別作為兩個服務處理。
zuul
進行路由分發和進行關聯oauth2服務
- Pom需要的依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency>
- 配置檔案
server: port: 10000 servlet: session: cookie: name: UISESSION spring: cloud: consul: host: localhost # Consul監聽埠8500 port: 8500 discovery: # 配置服務註冊到Consul上 register: true # 配置服務健康檢測地址 供Consul 呼叫 health-check-path: /api/health # consul 健康檢測頻率 health-check-interval: 15s # 配置註冊到consul 服務的id instance-id: ${spring.application.name}:${server.port} enabled: true service-name: ${spring.application.name} application: name: ecology-getway thymeleaf: cache: true zuul: host: connect-timeout-millis: 10000 socket-timeout-millis: 60000 routes: ratelimit-api: path: /ratelimit-api/** serviceId: service-client sensitiveHeaders: "*" login: path: /login/** sensitiveHeaders: "*" serviceId: server-login auth: path: /uaa/** serviceId: ecology-oauth2 strip-prefix: true custom-sensitive-headers: true user: path: /user/** serviceId: service-account-center ratelimit: key-prefix: ratelimit-api # 啟動限流服務 enabled: true behind-proxy: true default-policy: # 請求數量 limit: 100 # 請求總時間 quota: 20 # 統計視窗重新整理時間 refresh-interval: 60 # 限流型別 type: url ignored-services: '*' add-proxy-headers: true retryable: true sensitive-headers: security: oauth2: client: access-token-uri: http://localhost:${server.port}/uaa/oauth/token user-authorization-uri: http://localhost:${server.port}/uaa/oauth/authorize client-id: open-api resource: user-info-uri: http://localhost:${server.port}/uaa/user prefer-token-info: false
- springboot入口處進行配置 開啟zuul
@EnableZuulProxy
@SpringBootApplication
@EnableDiscoveryClient
- 增加我們的websecurity的配置
@Configuration @EnableWebSecurity @Order(SecurityProperties.BASIC_AUTH_ORDER - 3) class SecurityConfig : WebSecurityConfigurerAdapter() { override fun configure(http: HttpSecurity?) { http!! .csrf() .disable() } }
oauth2
Oauth2的服務模組
資源配置
根據自己的情況進行修改,是否部分資源可以不需要授權進行請求
@Configuration
@EnableResourceServer
class ResourceServerConfig : ResourceServerConfigurerAdapter(){
override fun configure(http: HttpSecurity?) {
http!!
.anonymous()
.disable()
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers("/api/**")
.fullyAuthenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(OAuth2AccessDeniedHandler())
}
}
授權服務
這裡採用了redis進行Token的儲存。
@Configuration
@EnableAuthorizationServer
class AuthorizationServerConfig : AuthorizationServerConfigurerAdapter(){
@Autowired
private lateinit var oAuth2DatabaseClientDetailsService: OAuth2DatabaseClientDetailsService
@Autowired
private lateinit var authenticationManager: AuthenticationManager
@Autowired
private lateinit var redisFactory: RedisConnectionFactory
@Bean
fun tokenStore(): TokenStore {
return RedisTokenStore(redisFactory)
}
override fun configure(security: AuthorizationServerSecurityConfigurer?) {
security!!
.tokenKeyAccess("permitAll()")
}
override fun configure(clients: ClientDetailsServiceConfigurer?) {
clients!!.withClientDetails(oAuth2DatabaseClientDetailsService)
}
override fun configure(endpoints: AuthorizationServerEndpointsConfigurer?) {
endpoints!!
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
}
}
web策略
@Configuration
class WebSecurityConfig : WebSecurityConfigurerAdapter(){
private var log: Logger = LoggerFactory.getLogger(WebSecurityConfig::class.java)
@Bean
fun userDetail():UserDetailsService {
return DataBaseUserDetailsService()
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
override fun configure(auth: AuthenticationManagerBuilder?) {
auth!!
.userDetailsService(userDetail())
.passwordEncoder(passwordEncoder())
}
@Bean
override fun authenticationManagerBean(): AuthenticationManager {
return super.authenticationManagerBean()
}
override fun configure(http: HttpSecurity?) {
http!!
.authorizeRequests()
.antMatchers("/", "/auth/**", "/api/health", "/oauth/**", "/default/**", "/login","/user")
.permitAll()
.anyRequest()
.authenticated()
}
override fun configure(web: WebSecurity?) {
web!!.ignoring().antMatchers("/resources/**")
}
/**
* describe: 返回對應的使用者名稱
* author 候帥
* date 2018/8/19 上午9:28
* @return 使用者名稱
*/
@Bean
fun auditorAwareBean(): String {
val authentication = SecurityContextHolder.getContext().authentication
if (authentication == null || AuthenticationTrustResolverImpl().isAnonymous(authentication))
return "@SYSTEM"
val principal = authentication.principal
return when (principal) {
is String -> principal
is UserDetails -> principal.username
else -> principal.toString()
}
}
}
使用者UserDetails服務
/**
* FileName: DataBaseUserDetailsService
* author: 候帥
* data: 18/08/2018 07:40
* Description: 自定義使用者身份獲取
* History:
*/
@Service
class DataBaseUserDetailsService :UserDetailsService {
private val log: Logger = LoggerFactory.getLogger(DataBaseUserDetailsService::class.java)
companion object {
private const val ROLE_PREFIX: String = "ROLE_"
}
@Autowired
private lateinit var userFeign: UserFeign
@Autowired
private lateinit var accessTokenRepository: AccessTokenRepository
@Autowired
private lateinit var clientDetailsRepository: ClientDetailsRepository
override fun loadUserByUsername(username: String?): UserDetails {
return Optional.ofNullable(userFeign.findUserInfo(username!!))
.map {
[email protected] User(it.account, it.password, it.roles.stream()
.map {
[email protected] SimpleGrantedAuthority(prefixRoleName(it))
}
.collect(Collectors.toList()))
}.orElseThrow {
[email protected] UsernameNotFoundException("User $username was not found in the database")
}
}
/**
* describe: 獲取客戶端的Token 內容
* author 候帥
* date 2018/8/18 下午10:21
* @param tokenId token對應的id
* @return 返回間隔時間
*/
fun loadClientByToken(tokenId: String): Triple<Long, String, Long> {
val clientId = accessTokenRepository
.findOneByTokenId(tokenId)
.map { [email protected] it.clientId }
.orElseThrow {
[email protected] UsernameNotFoundException("Token $tokenId was not found in the database")
}
val details = clientDetailsRepository.findOneByClientId(clientId).get()
val clientLimit = details.clientLimit
return Triple(clientLimit.intervalInMills, clientId, clientLimit.limits)
}
/**
* describe: 將未有字首的內容 新增
* author 候帥
* date 2018/8/18 下午10:20
* @param roleName 角色名
* @return 返回過濾的角色名
*/
fun prefixRoleName(roleName: String): String {
if (!StringUtils.isEmpty(roleName) && !roleName.startsWith(ROLE_PREFIX))
return ROLE_PREFIX + roleName
return roleName
}
}
配置檔案
server:
port: 10010
spring:
cloud:
consul:
host: localhost
# Consul監聽埠8500
port: 8500
discovery:
# 配置服務註冊到Consul上
register: true
# 配置服務健康檢測地址 供Consul 呼叫
health-check-path: /api/health
# consul 健康檢測頻率
health-check-interval: 15s
# 配置註冊到consul 服務的id
instance-id: ${spring.application.name}:${server.port}
enabled: true
service-name: ${spring.application.name}
application:
name: ecology-oauth2
redis:
# 設定資料庫索引
database: 0
host: localhost
port: 6379
password:
jedis:
pool:
max-active: 10
max-idle: 10
min-idle: 0
max-wait: -1ms
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/andy?useSSL=false
username: root
password: root
dbcp2:
# 初始化連線數
initial-size: 5
# 最小連線數
min-idle: 5
# 最大連線數
max-idle: 20
jpa:
hibernate:
ddl-auto: update
show-sql: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
profiles:
include: default-user-and-roles_route
ribbon:
eager-load:
enabled: false