用户认证
用户认证是与 REST API 交互的第一步。Jmix 必须通过这一步来识别用户,哪个用户发起了请求。Jmix 依据用户对请求添加权限/数据访问限制,以确保仅允许用户查看或者交互系统中允许的部分内容。
认证请求
如需使用 Jmix REST API 交互,需要经过 OAuth2 流程进行认证。下面的序列图解释了用 REST API 的一般交互过程:
首先,API 客户端需要使用认证请求获取一个访问 token。给 Jmix 发送一个 www-form-urlencoded
请求,请求的表单中包含 username 和 password:
POST http://localhost:8080/oauth/token
Authorization: Basic {{client_id}} {{client_secret}} (1)
Content-Type: application/x-www-form-urlencoded (2)
grant_type=password (3)
&username={{username}} (4)
&password={{password}}
1 | 认证请求本身也需要使用基本的 client_id 和 client_secret 进行认证。 |
2 | 认证请求的 content type 为 application/x-www-form-urlencoded 。 |
3 | grant_type 为 password ,指定认证类型。 |
4 | 用户的凭证,使用表单的 username 和 password 键值提供。 |
成功登录后,Jmix 在 HTTP 响应中返回访问 token:
{
"access_token": "CXE0w/9cOsnpSo8v2jEDoI8Qa3Y=",
"token_type": "bearer",
"refresh_token": "Hh2xCuZ7fgd35obagEBNGevF4ws=",
"expires_in": 31535999,
"scope": "rest-api",
"OAuth2.SESSION_ID": "5C46CDF266E8C8C15372887830B74F59"
}
access_token
属性值为访问 token,可以用在后续其他请求中。
更新 Token
Token 只是用作临时的凭证/密码。一段时间之后,token 就会过期,你需要请求一个新的 token。一个方法是要求用户使用凭证再做一次常规的认证请求。
不要为了图方便在你的客户端应用程序中存储用户的 username 和 password,以便用户不用再次输入凭证。如果需要的话,应该再次要求用户输入,或者使用 refresh token 防止 token 过期。 |
最初的认证请求返回体中包含一个 refresh_token
,可以用来创建新的访问 token。访问 token 的有效期相对比较短(Jmix 默认为 12 小时),而刷新 token 的有效期默认为 365 天。因此,可以刷新 token 非常适合用来做长期有效的凭证以获取新 token。
如需使用刷新 token 获取访问 token,可以用获取 token 的相同接口,但是 grant_type
不是 password
而是 refresh_token
。下面是使用刷新 token 获取新访问 token 的示例:
POST http://localhost:8080/oauth/token
Authorization: Basic {{client_id}} {{client_secret}}
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token (1)
&refresh_token=Hh2xCuZ7fgd35obagEBNGevF4ws= (2)
1 | grant_type 为 refresh_token ,表示登录的类型。 |
2 | 刷新 token 使用 refresh_token 键值提供。 |
返回结果包含一个新的访问 token,具有新的过期时间。使用这种方式,在 token 过期后无需向用户索要凭证继续使用 API。
发起 API 请求
对不同场景的 Jmix API,有两种使用访问 token 进行认证的方式。我们先看第一种主要的使用方式:通过 HTTP 请求头提供。
请求头认证
收到访问 token 后就可以发起 REST API 请求。访问 token 要在每个请求头的 Authorization
中提供,示例:
POST http://localhost:8080/rest
/entities
/rstex11_Customer
Authorization: Bearer CXE0w/9cOsnpSo8v2jEDoI8Qa3Y= (1)
{
name: "Randall Bishop"
}
1 | API 请求使用 Bearer 类型和访问 token 进行认证。 |
URL 参数认证
访问 token 还可以用于 URL 查询参数中。主要用在 HTTP 请求头无法设置的情况。比如,提供浏览器中的文件链接,或者渲染图片时。
下面的示例中,来自 文件 API 的图片需要在网页的 <img src="…" />
中展示。
此时,无法设置 HTTP 请求头,因此可以将 access_token
作为 URL 参数传入:
<img
src="http://localhost:8080/files
?access_token=CXE0w/9cOsnpSo8v2jEDoI8Qa3Y=
&fileRef=fs://2021/03/12/a3b6011d-9040-151e-7d17-f7ccdf75d72f.jpg?name=cat.jpg"
/>
匿名访问
默认情况下,所有的接口都需要先进行用户认证之后才能使用。但是也支持使用 Jmix 的匿名访问功能将某些 REST API 开放为匿名接口。此时,API 请求是通过用户 anonymous
发起的,此用户是 Jmix 应用程序默认自带的。
在没有使用 Authentication
请求头的情况下调用受保护的接口,会使用 anonymous
用户会话进行认证。
如需添加匿名访问的接口白名单,可在 jmix.rest.anonymous-url-patterns 应用程序属性设置 URL pattern。示例:
jmix.rest.anonymous-url-patterns = \
/rest/services/productService/getProductInformation,\
/rest/entities/Product,\
/rest/entities/Product/*
上面配置的最后一行是必要的,因为如果是更新或者删除 Product
实体,URL 最后还有一部分是实体 ID。
设置完成后,可以无需使用 Authorization
请求头与 ProductService
进行交互:
GET {{baseRestUrl}}
/services
/productService
/getProductInformation
?productId=123
# Authorization: not set
该请求会成功收到服务的响应:
{
"name": "Apple iPhone",
"productId": "123",
"price": 499.99
}
如需提供对某些 实体 接口的匿名访问,请确保 anonymous
用户有访问这些实体的权限。可以创建一个 资源角色,然后在 DatabaseUserRepository.initAnonymousUser()
方法中为 anonymous
用户分配该角色。示例:
@ResourceRole(name = "AnonymousRestRole", code = AnonymousRestRole.CODE, scope = "API")
public interface AnonymousRestRole {
String CODE = "anonymous-rest-role";
@EntityAttributePolicy(entityClass = Product.class,
attributes = "*",
action = EntityAttributePolicyAction.MODIFY)
@EntityPolicy(entityClass = Product.class,
actions = {EntityPolicyAction.READ, EntityPolicyAction.UPDATE})
void product();
}
@Primary
@Component("UserRepository")
public class DatabaseUserRepository extends AbstractDatabaseUserRepository<User> {
// ...
@Override
protected void initAnonymousUser(User anonymousUser) {
Collection<GrantedAuthority> authorities = getGrantedAuthoritiesBuilder()
.addResourceRole(AnonymousRestRole.CODE)
.build();
anonymousUser.setAuthorities(authorities);
}
}
匿名访问功能 不需要 anonymous 用户有 rest-minimal 角色。
|