Web应用接入OAuth2

上一篇博客介绍了OAuth2的基础概念,此篇博客将介绍对于web应用而言如何介入OAuth2,这里需要同时开启之前OAuth2的授权码模式的应用作为授权服务器,另外开启新的客户端应用,客户端应用代码在这里(备注:源码基本来源于bobo老师在网上公开的的demo代码)。

客户端服务启动在9001端口,启动后,会弹出altert的dialog框,这里输入在授权服务器的application.properties中设置的用户名和密码。

输入正确的用户名、密码后会显示OAuth Approve界面,Approve后,获取到接口信息并显示在页面上。

上面是整个演示的效果,接下来看看代码中国呢是如何实现的。 首先来看看SecurityConfiguration配置类,这个类通过继承WebSecurityConfigurerAdapter来控制哪些请求必须通过授权才能访问的资源。从这里的配置可以看到/和/index.html页面可以直接访问,其他URL必须授权后才能访问。

对于OAuth2而言,核心就是获取Token和使用Token,在客户端应用中通过RestTemplate获取授权码和token,然后带上token获取资源服务器的相关接口信息并显示在页面上。下面是获取Token并存入数据库的代码。这里通过SecurityContextHolder来获取当前认证的用户的上下文信息。通过日志打印可以看到ClientUser包含如下信息,显示的用户名和密码是在登陆框中输入的用户名和密码。

获取token的具体逻辑封装在AuthorizationCodeTokenService中,和前面通过post获取的过程一样,这里知识通过RestTemplate来获取而已。通过打印日志可以看到发送的获取token的POST请求和返回的token信息,如下所示

总结而言,整个代码实现的关键步骤有两部分:

1.通过继承 WebSecurityConfigurerAdapter来配置资源控制器的控制范围

2.通过RestTemplate来调用API获取code和token

上面用的RestTemplate,这里做一下简要介绍,RestTemplate是Spring提供的用于访问 Rest 服务的客户端库。下面是一些RestTemplate使用的小例子。

//1. 简单Get请求
String result = restTemplate.getForObject(rootUrl + "get1?para=my", String.class);
System.out.println("简单Get请求:" + result);

//2. 简单带路径变量参数Get请求
result = restTemplate.getForObject(rootUrl + "get2/{1}", String.class, 239);
System.out.println("简单带路径变量参数Get请求:" + result);

//3. 返回对象Get请求(注意需包含compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5')
ResponseEntity<Test1> responseEntity = restTemplate.getForEntity(rootUrl + "get3/339", Test1.class);
System.out.println("返回:" + responseEntity);
System.out.println("返回对象Get请求:" + responseEntity.getBody());

//4. 设置header的Get请求
HttpHeaders headers = new HttpHeaders();
headers.add("token", "123");
ResponseEntity<String> response = restTemplate.exchange(rootUrl + "get4", HttpMethod.GET, new HttpEntity<String>(headers), String.class);
System.out.println("设置header的Get请求:" + response.getBody());

//5. Post对象
Test1 test1 = new Test1();
test1.name = "buter";
test1.sex = 1;
result = restTemplate.postForObject(rootUrl + "post1", test1, String.class);
System.out.println("Post对象:" + result);

//6. 带header的Post数据请求
response = restTemplate.postForEntity(rootUrl + "post2", new HttpEntity<Test1>(test1, headers), String.class);
System.out.println("带header的Post数据请求:" + response.getBody());

//7. 带header的Put数据请求
//无返回值
restTemplate.put(rootUrl + "put1", new HttpEntity<Test1>(test1, headers));
//带返回值
response = restTemplate.exchange(rootUrl + "put1", HttpMethod.PUT, new HttpEntity<Test1>(test1, headers), String.class);
System.out.println("带header的Put数据请求:" + response.getBody());

//8. del请求
//无返回值
restTemplate.delete(rootUrl + "del1/{1}", 332);
//带返回值
response = restTemplate.exchange(rootUrl + "del1/332", HttpMethod.DELETE, null, String.class);
System.out.println("del数据请求:" + response.getBody());

getForObject和getForEntity 这两个方法都是采用get请求去获取数据,只是getForObject()比getForEntity()多包含了将HTTP转成POJO的功能。postForObject和postForEntity是发送Post请求,于Get请求相比较,Post请求需要构造request body类,也就是HttpEntity。下面是通过MultiValueMap构造body的小例子。

String url = "http://www.xxxx.com";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("userId", "3212xxxxxxxxxxxxxx");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
ResponseEntity<String> response = restTemplate.postForEntity( url, request , String.class );
System.out.println(response.getBody());

exchange()方法跟上面的方法不同之处在于它可以指定请求的HTTP类型。在前面的客户端代码中也通过MultiValueMap构造获取token的请求的。通过这个例子也实现了授权服务器和资源服务器的分离,另外,授权的token等信息也存入了数据库。

前面的例子里面refresh_token是空,且token过期时间是默认的43199(12小时),如果要添加token过期时间和生成refresh_token则修改授权服务器中的配置即可。

通过打印日志可以看到token的过期时间已经修改,且会生成refresh_token.

有了refresh_token,当从数据库获取token时,先判断有效时间,如果有效时间小于当前时间,那么就需要通过refresh_token获取新的token并存入数据库。

这里再补充解释下如何通过数据库存储token等信息,因为spring-security中就提供了UserDetails对象,所以第一步是implement userDetails,里面主要包括getClientUser等方法。

接着还需要定义ClientUser对象。因为getClientUser获取的就是ClientUser对象信息。这里存入数据库是采用JDBC的方式,所以ClientUser是一个Entity,内容如下:

除了对象定义,还创建了UserRepository class,负责对数据进行增删改查,因为有很多默认方法,例如通过save就可以存入数据库,故这里只自定义了findByUsername方法。

以上就是对web应用接入OAuth2的介绍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

taoli-qiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值