sprint oauth2 mysql_Spring Cloud OAuth2 教程

学习一下Spring Cloud OAuth2,我们分三个项目 eureka-server、service-auth、service-hi

3427549a148a?from=singlemessage

g9.png

1. 创建eureka-server项目

选择依赖 spring-cloud-starter-netflix-eureka-server

1.1 启动类里添加注释

@SpringBootApplication

@EnableEurekaServer

public class EurekaServerApplication {

public static void main(String[] args) {

SpringApplication.run(EurekaServerApplication.class, args);

}

}

1.2 application.yml

spring:

application:

name: eureka-server

server:

port: 8761

eureka:

instance:

hostname: localhost

client:

service-url:

defaultZone: http://localhost:8761/eureka/

fetch-registry: false

register-with-eureka: false

2 创建service-auth项目

2.1 用于获取授权token,项目上目录结构:

3427549a148a?from=singlemessage

g4.png

这里有个有趣的地方,如果包名config和customImpl和启动类不在同一个根包下,会扫不到包,此时必须在启动类上增加 @ComponentScan(basePackages = "包名")

2.2 创建项目依赖

spring-boot-starter-data-redis 把token存到redis中

spring-cloud-starter-netflix-eureka-client 做为EurekaClient

spring-cloud-starter-oauth2 是对spring-cloud-starter-security、spring-security-oauth2、spring-security-jwt这3个依赖的整合

spring-boot-starter-actuator

完整pom.xml

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.uaa.service

uaa-service

0.0.1-SNAPSHOT

jar

uaa-service

Demo project for Spring Boot

org.springframework.boot

spring-boot-starter-parent

2.0.4.RELEASE

UTF-8

UTF-8

1.8

Finchley.SR1

org.springframework.boot

spring-boot-starter-actuator

org.springframework.boot

spring-boot-starter-data-redis

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

org.springframework.cloud

spring-cloud-starter-oauth2

org.springframework.boot

spring-boot-starter-test

test

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

org.springframework.boot

spring-boot-maven-plugin

2.3 application.yml

spring:

application:

name: service-auth

redis:

host: 172.16.10.43

database: 0

server:

port: 9098

eureka:

client:

service-url:

defaultZone: http://localhost:8761/eureka/

application.yml中配置redis、注册中心

接下来分别继承 AuthorizationServerConfigurerAdapter和WebSecurityConfigurerAdapter

AuthorizationServerConfigurerAdapter 类中3个不同的configure方法分别

configure(ClientDetailsServiceConfigurer clients) 用来配置客户端详情服务(ClientDetailsService),客户端详情信息在这里进行初始化,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息;

configure(AuthorizationServerEndpointsConfigurer endpoints) 用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services),还有token的存储方式(tokenStore);

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

WebSecurityConfigurerAdapter

configure(HttpSecurity http) httpSecurity中配置所有请求的安全验证

注入Bean UserDetailsService

注入Bean AuthenticationManager 用来做验证

注入Bean PasswordEncoder

2.4 AuthorizationServerConfiguration继承AuthorizationServerConfigurerAdapter

@Configuration

@EnableAuthorizationServer

public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

@Autowired

AuthenticationManager authenticationManager;

@Autowired

RedisConnectionFactory redisConnectionFactory;

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

String finalSecret = "{bcrypt}" + new BCryptPasswordEncoder().encode("123456");

// 配置两个客户端,一个用于password认证一个用于client认证

clients.inMemory().withClient("client_1")

.resourceIds(Utils.RESOURCEIDS.ORDER)

.authorizedGrantTypes("client_credentials", "refresh_token")

.scopes("select")

.authorities("oauth2")

.secret(finalSecret)

.and().withClient("client_2")

.resourceIds(Utils.RESOURCEIDS.ORDER)

.authorizedGrantTypes("password", "refresh_token")

.scopes("server")

.authorities("oauth2")

.secret(finalSecret);

}

@Override

public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

endpoints.tokenStore(new MyRedisTokenStore(redisConnectionFactory))

.authenticationManager(authenticationManager)

.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);

}

@Override

public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {

// 允许表单认证

security.allowFormAuthenticationForClients();

}

}

2.5 SecurityConfiguration 继承 WebSecurityConfigurerAdapter

@Configuration

@EnableWebSecurity

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Bean

@Override

protected UserDetailsService userDetailsService() {

BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

String finalPassword = "{bcrypt}"+bCryptPasswordEncoder.encode("123456");

InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();

manager.createUser(User.withUsername("user_1").password(finalPassword).authorities("USER").build());

manager.createUser(User.withUsername("user_2").password(finalPassword).authorities("USER").build());

return manager;

}

@Bean

PasswordEncoder passwordEncoder() {

return PasswordEncoderFactories.createDelegatingPasswordEncoder();

}

@Bean

@Override

public AuthenticationManager authenticationManagerBean() throws Exception {

AuthenticationManager manager = super.authenticationManagerBean();

return manager;

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.requestMatchers().anyRequest()

.and()

.authorizeRequests()

.antMatchers("/oauth/**").permitAll();

}

}

这里在内在中创建了两个用户user_1和user_2,后续会以存mysql数据的方式来完善。

2.6 暴露Remote Token Services 接口

采用RemoteTokenServices这种方式对token进行验证,如果其他资源服务需要验证token,则需要远程调用授权服务暴露的验证token的api接口,验证token的API接口代码如下:

@RestController

@RequestMapping("/users")

public class UserController {

Logger logger = LoggerFactory.getLogger(UserController.class);

@RequestMapping(value = "/current", method = RequestMethod.GET)

public Principal getUser(Principal principal) {

logger.info(">>>>>>>>>>>>>>>>>>>>>>>>");

logger.info(principal.toString());

logger.info(">>>>>>>>>>>>>>>>>>>>>>>>");

return principal;

}

}

2.7 启动类

@SpringBootApplication

@EnableResourceServer

@EnableEurekaClient

public class ServiceAuthApplication {

public static void main(String[] args) {

SpringApplication.run(ServiceAuthApplication.class, args);

}

}

启动类上加上EnableResourceServer注解开启资源服务,因为程序需要对外暴露获取token的API和验证token的API所以该程序也是一个资源服务器。

到此,授权服务已经配置完成,可以访问,认证类型以password方式

3427549a148a?from=singlemessage

g2.png

3. 创建资源服务器 service-hi

创建项目的依赖 spring-cloud-starter-openfeign、spring-cloud-starter-oauth2、spring-cloud-starter-netflix-eureka-client、spring-boot-starter-web

3.1 以下是完整pom.xml

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.service.hi

service-hi

0.0.1-SNAPSHOT

jar

service-hi

Demo project for Spring Boot

org.springframework.boot

spring-boot-starter-parent

2.0.4.RELEASE

UTF-8

UTF-8

1.8

Finchley.SR1

org.springframework.boot

spring-boot-starter-web

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

org.springframework.cloud

spring-cloud-starter-oauth2

org.springframework.cloud

spring-cloud-starter-openfeign

org.springframework.boot

spring-boot-starter-test

test

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

org.springframework.boot

spring-boot-maven-plugin

3.2 配置文件 application.yml

eureka:

client:

service-url:

defaultZone: http://localhost:8761/eureka/

server:

port: 8765

spring:

application:

name: service-hi

security:

oauth2:

resource:

user-info-uri: http://localhost:9098/users/current

client:

id: client_2

client-secret: 123456

access-token-uri: http://localhost:9098/oauth/token

grant-type: client_credentials,password

scope: server

security.oauth2.resource.user-info-uri用于获取当前token的用户信息,配置security.oauth2.client的相关信息以及clientId、client-secret等信息要和service-auth中的配置一一对应。

3.3 配置Resource Server

@Configuration

@EnableResourceServer

@EnableGlobalMethodSecurity(prePostEnabled = true)

public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

@Override

public void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()

.antMatchers("/order/**").authenticated(); // 配置order访问控制,必须认证后才可以访问

}

}

添加EnableResourceServer注解开启资源服务的功能,加注解EnableGlobalMethodSecurity开户方法级别的保护,ResourceServerConfigurerAdapter是配置类,configure(HttpSecurity http)中只配置了"/order/**"需要验证。

3.4 配置OAuth2 Client

OAuth2 client用来访问被OAuth2保护的资源,service-hi作为OAuth2 Client,配置如下:

@EnableOAuth2Client

@EnableConfigurationProperties

@Configuration

public class OAuth2ClientConfig {

@Bean

@ConfigurationProperties(prefix = "security.oauth2.client")

public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {

return new ClientCredentialsResourceDetails();

}

@Bean

public RequestInterceptor oauth2FeignRequestInterceptor() {

return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails());

}

@Bean

public OAuth2RestTemplate clientCredentialsRestTemplate() {

return new OAuth2RestTemplate(clientCredentialsResourceDetails());

}

}

注解EnableOAuth2Client开启了OAuth2 Client功能,注入一个OAuth2RestTemplate 类型的Bean用于向service-auth服务请求。

3.5 写一个端点测试Controller TestEndPointController

@RestController

public class TestEndPointController {

Logger logger = LoggerFactory.getLogger(TestEndPointController.class);

@GetMapping("/product/{id}")

public String getProduct(@PathVariable String id) {

return "product id : " + id;

}

@GetMapping("/order/{id}")

public String getOrder(@PathVariable String id) {

return "order id : " + id;

}

@GetMapping("/getPrinciple")

public OAuth2Authentication getPrinciple(OAuth2Authentication oAuth2Authentication, Principal principal, Authentication authentication) {

logger.info(oAuth2Authentication.getUserAuthentication().getAuthorities().toString());

logger.info(oAuth2Authentication.toString());

logger.info("principal.toString() " + principal.toString());

logger.info("principal.getName() " + principal.getName());

logger.info("authentication: " + authentication.getAuthorities().toString());

return oAuth2Authentication;

}

}

3.6 启动类

@SpringBootApplication

@EnableEurekaClient

public class ServiceHiApplication {

public static void main(String[] args) {

SpringApplication.run(ServiceHiApplication.class, args);

}

}

到此资源服务的配置也完成,我们可以测试,依次启动 eureka-server、service-auth、service-hi

访问http://localhost:8761

3427549a148a?from=singlemessage

g7.png

访问oauth/token获取token信息 get方式请求:

也可以使用postman用post方式访问。

请求结果:

{

"access_token": "e9a93dff-fd58-4af3-b458-01fbb6079416",

"token_type": "bearer",

"refresh_token": "f31290cf-f421-49ba-8112-95a1a2fe9f09",

"expires_in": 40172,

"scope": "server"

}

{

"error": "unauthorized",

"error_description": "Full authentication is required to access this resource"

}

告诉你,没有权限访问该资源

3427549a148a?from=singlemessage

g8.png

product id : 1

{

"authorities": [

{

"authority": "USER"

}

],

"details": {

"remoteAddress": "0:0:0:0:0:0:0:1",

"sessionId": "8F2D30BA614CA41B6AA03D2A4650EA3E",

"tokenValue": "e9a93dff-fd58-4af3-b458-01fbb6079416",

"tokenType": "Bearer",

"decodedDetails": null

},

"authenticated": true,

"userAuthentication": {

"authorities": [

{

"authority": "USER"

}

],

"details": {

"authorities": [

{

"authority": "USER"

}

],

"details": {

"remoteAddress": "127.0.0.1",

"sessionId": null,

"tokenValue": "e9a93dff-fd58-4af3-b458-01fbb6079416",

"tokenType": "Bearer",

"decodedDetails": null

},

"authenticated": true,

"userAuthentication": {

"authorities": [

{

"authority": "USER"

}

],

"details": {

"grant_type": "password",

"scope": "server",

"client_secret": "123456",

"client_id": "client_2",

"username": "user_1"

},

"authenticated": true,

"principal": {

"password": null,

"username": "user_1",

"authorities": [

{

"authority": "USER"

}

],

"accountNonExpired": true,

"accountNonLocked": true,

"credentialsNonExpired": true,

"enabled": true

},

"credentials": null,

"name": "user_1"

},

"oauth2Request": {

"clientId": "client_2",

"scope": [

"server"

],

"requestParameters": {

"grant_type": "password",

"scope": "server",

"client_id": "client_2",

"username": "user_1"

},

"resourceIds": [],

"authorities": [

{

"authority": "oauth2"

}

],

"approved": true,

"refresh": false,

"redirectUri": null,

"responseTypes": [],

"extensions": {},

"grantType": "password",

"refreshTokenRequest": null

},

"principal": {

"password": null,

"username": "user_1",

"authorities": [

{

"authority": "USER"

}

],

"accountNonExpired": true,

"accountNonLocked": true,

"credentialsNonExpired": true,

"enabled": true

},

"credentials": "",

"clientOnly": false,

"name": "user_1"

},

"authenticated": true,

"principal": "user_1",

"credentials": "N/A",

"name": "user_1"

},

"clientOnly": false,

"principal": "user_1",

"credentials": "",

"oauth2Request": {

"clientId": null,

"scope": [],

"requestParameters": {},

"resourceIds": [],

"authorities": [],

"approved": true,

"refresh": false,

"redirectUri": null,

"responseTypes": [],

"extensions": {},

"grantType": null,

"refreshTokenRequest": null

},

"name": "user_1"

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值