改进目标初步定为:
(1)在数据库中保存安全认证数据,包括用户、客户端、验证码和令牌等。
(2)将认证服务器和资源服务器拆分。
其实这也是基于之前下载的开源代码。向源码作者致敬。
本实例分为下面2个项目:
(1)authorization-server——认证服务器。
(2)resource-server——对外提供接口的资源服务,也就是被保护的对象。
1.认证服务器authorization-server
这里先记录一下authorization-server的实现过程:
1.1搭建MySQL数据库服务器
这里选择MySQL数据库存储安全认证数据,于是用了周日一上午的时间现在安装MySQL数据库,各种配置不多记录了,与本文主题无关。
1.2数据库配置文件
在application
.yml中配置与数据库有关的参数,数据库连接字符串代码如下:
spring.datasource.url=jdbc:mysql://localhost:3306/oauth2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC
这里只要知道本实例使用的数据库是oauth2就可以了,其他都没什么说的。
下面记录一下本实例使用到的数据库表。首先,本实例中定义了2个bean:Role和User,最初以为需要创建这2个表,后来经过调试才发现,其实这并不是表名,只是用于接收查询数据库结果的bean。
那么存储用户和角色数据的表名是什么呢?在
user-mapper.xml中其实可以找到线索,分别是
springcloud_user和
springcloud_role。从名字就可以看出来,这是spring
cloud定义的表。另外还发现了一个用户和角色之间的关系表springcloud_user_role。
至于表结构,源代码中没有提及,只能百度。找到了一篇《spring-security-oauth2的mysql数据表》,网址如下:
https://blog.youkuaiyun.com/qq_27384769/article/details/79440449
这里有相关表字段的详细说明:
http://andaily.com/spring-oauth-server/db_table_description.html
上面2个网页中表结构及建表语句一应俱全,如果没有百度,应该怎样学习新技术?恐怕要买N本厚书
……。
经过调试,最终确定,本实例需要使用的数据库表如下:
l用户表
springcloud_user;
l角色表
springcloud_role;
l用户-角色关系表
springcloud_user_role;
l客户端信息表oauth_client_details;
l授权表oauth_approvals;
l令牌表oauth_access_token;
l验证码表oauth_code;
l刷新令牌表oauth_access_token
调试的时候没有注意到,
springcloud_user、
springcloud_role和
springcloud_user_role这3个表其实是借用
springcloud_前缀的伪
springcloud表,其实是开源项目原作者自己创建的。要不怎么需要单独写一个
user-mapper.xml来从这3个表读数据呢。而且各种查询都找不到它们的任何资料
……看来,研究后的梳理也是很重要的,否则有些细节还是容易被蒙蔽。这3个表的表结构就只能根据
user-mapper.xml和前面提到的2个bean来猜测着创建了。
1.3关于
MyBatis的配置
本实例与
MyBatis的集成并不是通过配置文件,而是通过一个配置类
MyBatisConfiguration实现的。其中指定了数据源
dataSource、
设置别名包
和
设置mapper映射文件所在的包
。
1.4关于认证服务器的配置
类
Oauth2AuthorizationServerConfiguration用于设置认证服务器的配置,比较主要的代码包括通过下面的代码指定客户端配置方式:
@Override
public void configure(ClientDetailsServiceConfigurer
clients)
throws Exception {
//
数据库管理client,从dataSource配置的数据源读取客户端数据
clients.withClientDetails(new
JdbcClientDetailsService(dataSource))
}
这里指定从数据库(oauth_client_details)
读取客户端数据
。
通过下面的代码指定端点(认证和获取token的端点)的配置方式:
@Override
publicvoidconfigure(AuthorizationServerEndpointsConfigurerendpoints)
throwsException
{
// 用户信息查询服务
endpoints.userDetailsService(userDetailsService);
//
数据库管理access_token和refresh_token
TokenStoretokenStore=newJdbcTokenStore(dataSource);
endpoints.tokenStore(tokenStore);
// 数据库管理
令牌库
DefaultTokenServicestokenServices=newDefaultTokenServices();
tokenServices.setTokenStore(tokenStore);
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(newJdbcClientDetailsService(
dataSource));
//
tokenServices.setAccessTokenValiditySeconds(180);
//
tokenServices.setRefreshTokenValiditySeconds(180);
endpoints.tokenServices(tokenServices);
// 数据库管理授权码
endpoints.authorizationCodeServices(newJdbcAuthorizationCodeServices(
dataSource));
// 数据库管理授权信息
ApprovalStoreapprovalStore=newJdbcApprovalStore(dataSource);
endpoints.approvalStore(approvalStore);
}
总之,都是通过数据库管理各种安全数据。一旦这么设置了数据库里如果没有相应的表就会报错。
1.5关于安全的配置
类
SecurityConfiguration用于设置安全的配置,比较主要的代码包括通过下面的代码指定不需认证就可以访问的页面:
@Override
protected void configure(HttpSecurity http) throws
Exception {
http.requestMatchers()
.antMatchers("/login", "/login-error",
"/oauth/authorize",
"/oauth/token").and().authorizeRequests()
.antMatchers("/login").permitAll().anyRequest().authenticated();
// 登录页面
http.formLogin().loginPage("/login").failureUrl("/login-error");
// 禁用CSRF
http.csrf().disable();
}
1.6自定义登录和授权页面
在1.5中的代码已经指定了登录路径为/login,登录错误页面的路径为/login-error。
对应的前端页面保存在resources\templates\statics\login.html。
这些基本的Spring
MVC编程没什么可说的,唯一没有搞清楚的是为什么提交用户名和密码的时候回交由Spring
Security进行验证,好在这个问题并不在此。因为数据交换中心的直接使用者并不是个人用户,而是上层应用,所以不会要求用户登录,而是根据上层应用的Client-id和Client-Secret进行身份验证。索性绕过这个小坎,忽略此问题,没有太多的时间了......
成功登录后会跳转至/oauth/confirm_access,这一点恐怕是Spring
Security实现的。Controller和前端页面就不具体记录了,反正不关心这个,授权页面会通过permitAll()绕过。