oauth2授权码登录源码php,Spring Boot OAuth2 单点登录 授权码模式

实现OAuth2单点登录需要准备3个springboot服务

资源服务

授权服务

用户访问服务

思路

通过用户访问服务,访问资源服务,得到异常401(未授权)

向资源服务器发送请求,获取授权码code

再向资源服务器发送得到的授权码code,获得access_token

access_token放在请求头,再去请求资源服务器

资源服务

spring的oauth2依赖为:

//包含了spring-security

implementation 'org.springframework.cloud:spring-cloud-starter-oauth2'

创建资源服务器配置:

@EnableOAuth2Sso //添加这个注解才会跳转到授权服务器

@Configuration

@EnableResourceServer//资源服务器

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)

public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter {

@Override

public void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()

.antMatchers("/actuator/**").permitAll() //放行了健康检查的接口

.anyRequest().authenticated()

}

}

yml配置文件

5002是授权服务器的端口号

#配置oauth2的地址,通过地址进行身份验证,如果设置错误或者不设置,会导致无法验证

security:

oauth2:

client:

client-id: 123 #授权服务器配置

client-secret: 123 #授权服务器配置

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

user-authorization-uri: http://localhost:5002/oauth/authorize

resource:

token-info-uri: http://localhost:5002/oauth/chec

资源服务器就是依靠配置文件中的地址来确认token是否有效

授权服务

添加依赖:

implementation 'org.springframework.cloud:spring-cloud-starter-oauth2'

本质上还是使用spring security做验证

简单设置登陆的用户名密码

spring:

application:

name: oauth2-auth-sqr

security:

user:

name: 123

password: 123

配置授权服务器

@Configuration

@EnableAuthorizationServer //授权服务器

public class Oauth2AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {

@Override

public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {

clients.inMemory()

.withClient("123")

.secret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("123")) //客户端 id/secret

.authorizedGrantTypes("authorization_code", "refresh_token") //授权码模式

.scopes("all")

.redirectUris("http://localhost:5003/user/code")

.autoApprove(true) //自动审批

.accessTokenValiditySeconds(36000)//有效期10hour

;

}

@Override

public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {

/* 配置token获取合验证时的策略 */

security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()").allowFormAuthenticationForClients();

}

}

代码中authorizedGrantTypes设置的是授权模式为授权码模式

redirectUris写的是用户访问服务自定义的接口,用来接收授权码code

spring security的配置

@EnableWebSecurity

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)

public class Oauth2WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

@Override

protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()

.anyRequest().authenticated()

//放行登录和身份验证接口

.antMatchers("/login").permitAll()

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

.and()

.formLogin().permitAll()

.and()

//要是没有登录,抛出401异常

// .exceptionHandling()

// .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))

// .and()

.csrf().disable();

}

}

用户访问服务

不需要引入oauth2的依赖

首先配置 RestTemplate,使得其能够允许所有重定向

@Configuration

public class RestTemplateConfig {

@Bean

public RestTemplate restTemplate() {

HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();

HttpClient httpClient = HttpClientBuilder.create()

//允许所有请求的重定向

.setRedirectStrategy(new LaxRedirectStrategy())

.build();

factory.setHttpClient(httpClient);

factory.setConnectTimeout(15000);

factory.setReadTimeout(5000);

return new RestTemplate(factory);

}

}

用来获取授权码的controller

@Slf4j

@RestController

@RequestMapping("/user")

public class UserController {

@Autowired

RestTemplate restTemplate;

/**

* 前端接入的登录接口

*

* 需要改为post请求,传入用户名和密码

*

*

* @throws Exception

*/

@GetMapping("/login")

public ResponseEntity login() throws Exception {

//spring-cloud-oauth2 登录验证的地址

URI oauthUrl = new URIBuilder("http://localhost:5002/oauth/authorize")

.addParameter("client_id", "123")

.addParameter("response_type", "code")

.addParameter("redirect_uri", "http://localhost:5003/user/code")

.build();

CloseableHttpClient httpClient = HttpClientBuilder.create().build();

//http 配置信息

RequestConfig requestConfig = RequestConfig.custom()

.setConnectTimeout(5000) // 设置连接超时时间(单位毫秒)

.setConnectionRequestTimeout(5000)// 设置请求超时时间(单位毫秒)

.setSocketTimeout(5000)// socket读写超时时间(单位毫秒)

.setRedirectsEnabled(false)// 设置是否允许重定向(默认为true)

.build();

HttpGet oauthHttpGet = new HttpGet(oauthUrl);

oauthHttpGet.setConfig(requestConfig);//将上面的配置信息 运用到这个Get请求里

//响应模型 由客户端执行(发送)Get请求

CloseableHttpResponse response = httpClient.execute(oauthHttpGet);

//返回的是重定向302

if (response.getStatusLine().getStatusCode() == HttpStatus.FOUND.value()) {

//获取Set-Cookie成为登录页面的cookie

String setCookie = response.getFirstHeader("Set-Cookie").getValue();

String cookie = setCookie.substring(0, setCookie.indexOf(";"));

//登录页面获取token

MultiValueMap loginParams = new LinkedMultiValueMap<>();

loginParams.add("username", "123");

loginParams.add("password", "123");

//添加cookie

HttpHeaders loginHeader = new HttpHeaders();

loginHeader.set("Cookie", cookie);

HttpEntity> loginEntity =

new HttpEntity<>(loginParams, loginHeader);

String loginUrl = "http://localhost:5002/login";

ResponseEntity loginResult = restTemplate.

postForEntity(loginUrl, loginEntity, String.class);

log.info("---- 登录请求结果:{} ----", loginResult);

return loginResult;

}

// 释放资源

httpClient.close();

response.close();

return null;

}

/**

* 获取授权码code,再请求获取token

*

* @param code

* @return

*/

@GetMapping("/code")

public ResponseEntity code(@RequestParam("code") String code) {

log.info("---- 获取授权码:{} ----", code);

MultiValueMap tokenParams = new LinkedMultiValueMap<>();

tokenParams.add("grant_type", "authorization_code");

tokenParams.add("code", code);

tokenParams.add("client_id", "123");

tokenParams.add("client_secret", "123");

tokenParams.add("redirect_uri", "http://localhost:5003/user/code");

tokenParams.add("scope", "all");

HttpHeaders tokenHeader = new HttpHeaders();

tokenHeader.set("Content-Type", "multipart/form-data");

HttpEntity> requestEntity =

new HttpEntity<>(tokenParams, tokenHeader);

ResponseEntity tokenResult = restTemplate.postForEntity(

"http://localhost:5002/oauth/token", requestEntity, String.class);

log.info("---- 获取token结果:{} ----", tokenResult);

String token = new JsonParser().parse(tokenResult.getBody()).

getAsJsonObject().get("access_token").getAsString();

log.info("---- access_token:{} ----", token);

//访问资源服务,仅仅能用来验证登录效果

HttpHeaders resourceHeader = new HttpHeaders();

resourceHeader.set("Authorization", "Bearer " + token);

ResponseEntity resourceResult = restTemplate.exchange(

"http://localhost:5004/getResource", HttpMethod.GET,

new HttpEntity(null, resourceHeader), String.class);

log.info("获取资源的结果:{}", resourceResult);

return tokenResult;

}

}

/user/login

这个接口可以代替登录接口,实际使用需要改为post请求,传入用户名和密码

由于访问http://localhost:5002/oauth/authorize会自动重定向到spring security的登录页面,此时无法传入用户名和密码,所以不能使用restTemplate 发起请求

/user/login

获得状态码code之后对"http://localhost:5002/oauth/token"发起请求能够获得access_token;请求传入的参数与在授权服务器中配置的一致即可

2.获取access_token之后,放在请求头中,即可请求成功

resourceHeader.set("Authorization", "Bearer " + token);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值