# 如何通过 `jap-ids` 实现 OAuth 2.0 + OIDC 协议?
完整示例代码参考:[https://gitee.com/fujieid/jap-ids-demo](https://gitee.com/fujieid/jap-ids-demo)
## 第一步:实现 ids 接口
1. 实现 `IdsClientDetailService.java`
```java
package com.fujieid.ids.demo.service;
import com.fujieid.jap.ids.model.ClientDetail;
import com.fujieid.jap.ids.model.enums.GrantType;
import com.fujieid.jap.ids.model.enums.ResponseType;
import com.fujieid.jap.ids.provider.IdsScopeProvider;
import com.fujieid.jap.ids.service.IdsClientDetailService;
import com.fujieid.jap.ids.util.OauthUtil;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @date 2021-04-14 10:27
* @since 1.0.0
*/
@Service
public class IdsClientDetailServiceImpl implements IdsClientDetailService {
public List<ClientDetail> clientDetails = new LinkedList<>();
public IdsClientDetailServiceImpl() {
clientDetails.add(new ClientDetail()
.setId("1")
.setAppName("适应所有场景")
.setClientId(OauthUtil.generateClientId())
.setClientSecret(OauthUtil.generateClientSecret())
.setRedirectUri("http://localhost:8080")
.setScopes(String.join(" ", IdsScopeProvider.getScopeCodes()))
.setGrantTypes(String.join(" ", GrantType.grantTypes()))
.setResponseTypes(String.join(" ", Arrays.asList(ResponseType.CODE.getType(), ResponseType.TOKEN.getType(), ResponseType.ID_TOKEN.getType(), ResponseType.NONE.getType())))
.setAvailable(true)
);
}
/**
* 通过 client_id 查询客户端信息
*
* @param clientId 客户端应用id
* @return AppOauthClientDetails
*/
@Override
public ClientDetail getByClientId(String clientId) {
return clientDetails.stream().filter(client -> client.getClientId().equals(clientId)).findFirst().orElse(null);
}
/**
* Add client
*
* @param clientDetail Client application details
* @return ClientDetail
*/
@Override
public ClientDetail add(ClientDetail clientDetail) {
return IdsClientDetailService.super.add(clientDetail);
}
/**
* Modify the client
*
* @param clientDetail Client application details
* @return ClientDetail
*/
@Override
public ClientDetail update(ClientDetail clientDetail) {
return IdsClientDetailService.super.update(clientDetail);
}
/**
* Delete client by primary key
*
* @param id Primary key of the client application
* @return boolean
*/
@Override
public boolean removeById(String id) {
return IdsClientDetailService.super.removeById(id);
}
/**
* Delete client by client id
*
* @param clientId Client application id
* @return ClientDetail
*/
@Override
public boolean removeByClientId(String clientId) {
return IdsClientDetailService.super.removeByClientId(clientId);
}
/**
* 获取所有 client detail
*
* @return List
*/
@Override
public List<ClientDetail> getAllClientDetail() {
return clientDetails;
}
}
```
2. 实现 `IdsIdentityService.java`
```java
package com.fujieid.ids.demo.service;
import com.fujieid.jap.ids.config.JwtConfig;
import com.fujieid.jap.ids.service.IdsIdentityService;
import org.springframework.stereotype.Service;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @date 2021-04-16 16:32
* @since 1.0.0
*/
@Service
public class IdsIdentityServiceImpl implements IdsIdentityService {
/**
* Get the jwt token encryption key string
*
* @param identity User/organization/enterprise identification
* @return Encryption key string in json format
*/
@Override
public String getJwksJson(String identity) {
return IdsIdentityService.super.getJwksJson(identity);
}
/**
* Get the configuration of jwt token encryption
*
* @param identity User/organization/enterprise identification
* @return Encryption key string in json format
*/
@Override
public JwtConfig getJwtConfig(String identity) {
return IdsIdentityService.super.getJwtConfig(identity);
}
}
```
3. 实现 `IdsUserService.java`
```java
package com.fujieid.ids.demo.service;
import com.fujieid.jap.ids.model.UserInfo;
import com.fujieid.jap.ids.service.IdsUserService;
import org.springframework.stereotype.Service;
import java.util.LinkedList;
import java.util.List;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @date 2021-04-14 10:27
* @since 1.0.0
*/
@Service
public class IdsUserServiceImpl implements IdsUserService {
public List<UserInfo> userInfoList = new LinkedList<>();
public IdsUserServiceImpl() {
for (int i = 0; i < 10; i++) {
UserInfo userInfo = new UserInfo();
userInfoList.add(userInfo
.setId(i + "")
.setUsername("test"));
}
}
@Override
public UserInfo loginByUsernameAndPassword(String username, String password) {
return userInfoList.stream().filter(userInfo -> userInfo.getUsername().equals(username)).findFirst().orElse(null);
}
/**
* Get user info by userid.
*
* @param userId userId of the business system
* @return JapUser
*/
@Override
public UserInfo getById(String userId) {
return userInfoList.stream().filter(userInfo -> userInfo.getId().equals(userId)).findFirst().orElse(null);
}
/**
* Get user info by username.
* <p>
* It is suitable for the {@code jap-simple} module
*
* @param username username of the business system
* @return JapUser
*/
@Override
public UserInfo getByName(String username) {
return userInfoList.stream().filter(userInfo -> userInfo.getUsername().equals(username)).findFirst().orElse(null);
}
}
```
注:`jap-ids` 默认提供了基于内存的缓存方案,如果不能满足你的业务场景,可以实现自定义的缓存:
```java
package com.fujieid.ids.demo.service;
import com.fujieid.jap.core.cache.JapCache;
import java.io.Serializable;
/**
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @date 2021-04-17 20:06
* @since 1.0.0
*/
public class IdsCacheImpl implements JapCache {
/**
* Set cache
*
* @param key Cache key
* @param value Cache value after serialization
*/
@Override
public void set(String key, Serializable value) {
}
/**
* Set the cache and specify the expiration time of the cache
*
* @param key Cache key
* @param value Cache value after serialization
* @param timeout The expiration time of the cache, in milliseconds
*/
@Override
public void set(String key, Serializable value, long timeout) {
}
/**
* Get cache value
*
* @param key Cache key
* @return Cache value
*/
@Override
public Serializable get(String key) {
return null;
}
/**
* Determine whether a key exists in the cache
*
* @param key Cache key
* @return boolean
*/
@Override
public boolean containsKey(String key) {
return false;
}
/**
* Delete the key from the cache
*
* @param key Cache key
*/
@Override
public void removeKey(String key) {
}
}
```
然后通过 `IdsContext` 的 `setCache` 方法设置自定义的 `cache` 实现。
## 第二步:注册 ids 上下文
通过 `JapIds.registerContext` 方法注册 ids 上下文,配置全局参数。
```java
// 注册 JAP IDS 上下文
JapIds.registerContext(new IdsContext()
.setUserService(idsUserS