项目场景:
言归正传,我们上一篇文章搭建的spring security显然不符合我们的需求,因此我们要在原来的基础上引入oauth.通过jwt的形式来完成登录模块。本篇文章我们只是引入oauth。
技术详解:
我们之前的配置只不过是引入了spring security,现在我们要加入oauth。
第一步:配置数据库
create table oauth_client_details (
client_id VARCHAR(256) PRIMARY KEY,
resource_ids VARCHAR(256),
client_secret VARCHAR(256),
scope VARCHAR(256),
authorized_grant_types VARCHAR(256),
web_server_redirect_uri VARCHAR(256),
authorities VARCHAR(256),
access_token_validity INTEGER,
refresh_token_validity INTEGER,
additional_information VARCHAR(4096),
autoapprove VARCHAR(256)
);
只需要配置这个表即可,因为最后的token信息我打算放到redis里面。表的字段描述如下
表名 | 字段名 | 字段说明 |
---|---|---|
oauth_client_details | client_id | 主键,必须唯一,不能为空. 用于唯一标识每一个客户端(client); 在注册时必须填写(也可由服务端自动生成). 对于不同的grant_type,该字段都是必须的. 在实际应用中的另一个名称叫appKey,与client_id是同一个概念. |
resource_ids | 客户端所能访问的资源id集合,多个资源时用逗号(,)分隔,如: "unity-resource,mobile-resource". 该字段的值必须来源于与 security.xml 中标签‹oauth2:resource-server 的属性resource-id 值一致. 在security.xml 配置有几个‹oauth2:resource-server 标签, 则该字段可以使用几个该值. 在实际应用中, 我们一般将资源进行分类,并分别配置对应的 ‹oauth2:resource-server ,如订单资源配置一个‹oauth2:resource-server , 用户资源又配置一个‹oauth2:resource-server . 当注册客户端时,根据实际需要可选择资源id,也可根据不同的注册流程,赋予对应的资源id. | |
client_secret | 用于指定客户端(client)的访问密匙; 在注册时必须填写(也可由服务端自动生成). 对于不同的grant_type,该字段都是必须的. 在实际应用中的另一个名称叫appSecret,与client_secret是同一个概念. | |
scope | 指定客户端申请的权限范围,可选值包括read,write,trust;若有多个权限范围用逗号(,)分隔,如: "read,write". scope的值与 security.xml 中配置的‹intercept-url 的access 属性有关系. 如‹intercept-url 的配置为 则说明访问该URL时的客户端必须有read权限范围. write的配置值为SCOPE_WRITE, trust的配置值为SCOPE_TRUST. 在实际应该中, 该值一般由服务端指定, 常用的值为read,write. | |
authorized_grant_types | 指定客户端支持的grant_type,可选值包括authorization_code,password,refresh_token,implicit,client_credentials, 若支持多个grant_type用逗号(,)分隔,如: "authorization_code,password". 在实际应用中,当注册时,该字段是一般由服务器端指定的,而不是由申请者去选择的,最常用的grant_type组合有: "authorization_code,refresh_token"(针对通过浏览器访问的客户端); "password,refresh_token"(针对移动设备的客户端). implicit与client_credentials在实际中很少使用. | |
web_server_redirect_uri | 客户端的重定向URI,可为空, 当grant_type为authorization_code 或implicit 时, 在Oauth的流程中会使用并检查与注册时填写的redirect_uri是否一致. 下面分别说明:
| |
authorities | 指定客户端所拥有的Spring Security的权限值,可选, 若有多个权限值,用逗号(,)分隔, 如: "ROLE_UNITY,ROLE_USER". 对于是否要设置该字段的值,要根据不同的grant_type来判断, 若客户端在Oauth流程中需要用户的用户名(username)与密码(password)的( authorization_code ,password ), 则该字段可以不需要设置值,因为服务端将根据用户在服务端所拥有的权限来判断是否有权限访问对应的API. 但如果客户端在Oauth流程中不需要用户信息的( implicit ,client_credentials ), 则该字段必须要设置对应的权限值, 因为服务端将根据该字段值的权限来判断是否有权限访问对应的API. (请在spring-oauth-client项目中来测试不同grant_type时authorities的变化) | |
access_token_validity | 设定客户端的access_token的有效时间值(单位:秒),可选, 若不设定值则使用默认的有效时间值(60 * 60 * 12, 12小时). 在服务端获取的access_token JSON数据中的 expires_in 字段的值即为当前access_token的有效时间值. 在项目中, 可具体参考 DefaultTokenServices.java 中属性accessTokenValiditySeconds . 在实际应用中, 该值一般是由服务端处理的, 不需要客户端自定义. | |
refresh_token_validity | 设定客户端的refresh_token的有效时间值(单位:秒),可选, 若不设定值则使用默认的有效时间值(60 * 60 * 24 * 30, 30天). 若客户端的grant_type不包括 refresh_token ,则不用关心该字段 在项目中, 可具体参考DefaultTokenServices.java 中属性refreshTokenValiditySeconds . 在实际应用中, 该值一般是由服务端处理的, 不需要客户端自定义. | |
additional_information | 这是一个预留的字段,在Oauth的流程中没有实际的使用,可选,但若设置值,必须是JSON格式的数据,如: 按照spring-security-oauth 项目中对该字段的描述 Additional information for this client, not need by the vanilla OAuth protocol but might be useful, for example,for storing descriptive information. (详见 ClientDetails.java 的getAdditionalInformation() 方法的注释) 在实际应用中, 可以用该字段来存储关于客户端的一些其他信息,如客户端的国家,地区,注册时的IP地址等等. | |
create_time | 数据的创建时间,精确到秒,由数据库在插入数据时取当前系统时间自动生成(扩展字段) | |
autoapprove | 设置用户是否自动Approval操作, 默认值为 'false', 可选值包括 'true','false', 'read','write'. 该字段只适用于grant_type="authorization_code"的情况,当用户登录成功后,若该值为'true'或支持的scope值,则会跳过用户Approve的页面, 直接授权. | |
在项目中,主要操作 |
第二步:添加配置文件
OAuth2Config.java
@EnableAuthorizationServer
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetails());
}
/**
* 配置clientDetailsService是jdbc
*/
@Bean
public ClientDetailsService clientDetails() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception
{
security.allowFormAuthenticationForClients();
security.checkTokenAccess("isAuthenticated()");
security.tokenKeyAccess("permitAll()");
}
}
好了,这里的话只需要使用postMan请求/oauth/token即可.