feat(auth): 添加通行密钥认证功能
- 新增 PasskeyAuthorizationController 控制器,提供注册与验证通行密钥的接口 - 创建 UserCredential 实体类及对应的 Mapper,用于存储用户凭证信息 - 实现 CredentialRepository 接口,支持通行密钥的查询与管理逻辑 - 新增 PasskeyAuthorizationService 接口及其实现,处理通行密钥的注册和验证流程 - 添加 PasskeyProperties 配置类,读取通行密钥相关配置项 - 引入 ehcache 缓存配置与工具类 CacheService,用于临时存储认证过程中的数据 - 配置 RelyingParty bean,支撑 WebAuthn 认证流程 - 在 pom.xml 中引入 fastjson2、webauthn-server-core 和 ehcache依赖 - 新增 application-dev.yml与 application-prod.yml 配置文件,区分环境变量 - 设置 spring.profiles.active 默认为 dev 环境
This commit is contained in:
parent
6ceab3cf86
commit
ecfeb0e9f5
16
pom.xml
16
pom.xml
@ -72,6 +72,22 @@
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<version>1.39.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.52</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.yubico</groupId>
|
||||
<artifactId>webauthn-server-core</artifactId>
|
||||
<version>2.7.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->
|
||||
<dependency>
|
||||
<groupId>org.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
package com.kane.animo.auth.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.kane.animo.auth.service.PasskeyAuthorizationService;
|
||||
import com.kane.animo.model.R;
|
||||
import com.yubico.webauthn.exception.RegistrationFailedException;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 通行密钥
|
||||
* @author Kane
|
||||
* @since 2025/11/7 17:40
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/passkey")
|
||||
public class PasskeyAuthorizationController {
|
||||
|
||||
@Resource
|
||||
private PasskeyAuthorizationService service;
|
||||
|
||||
/**
|
||||
* 获取通行密钥创建参数
|
||||
* @return 创建参数
|
||||
*/
|
||||
@GetMapping("/registration/options")
|
||||
public R<String> getPasskeyRegistrationOptions() throws JsonProcessingException {
|
||||
return R.success(service.startPasskeyRegistration());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证通行密钥
|
||||
* @param credential 凭证
|
||||
*/
|
||||
@PostMapping("/registration")
|
||||
public R<Void> verifyPasskeyRegistration(@RequestBody String credential) throws RegistrationFailedException, IOException {
|
||||
service.finishPasskeyRegistration(credential);
|
||||
return R.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通行密钥验证参数
|
||||
* @param httpServletRequest 请求
|
||||
* @return 验证参数
|
||||
*/
|
||||
@GetMapping("/assertion/options")
|
||||
public R<String> getPasskeyAssertionOptions(HttpServletRequest httpServletRequest) {
|
||||
return R.success(service.startPasskeyAssertion(httpServletRequest.getSession().getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证通行密钥
|
||||
* @param httpServletRequest 请求
|
||||
* @param credential 凭证
|
||||
*/
|
||||
@PostMapping("/assertion")
|
||||
public R<Void> verifyPasskeyAssertion(HttpServletRequest httpServletRequest, @RequestBody String credential) {
|
||||
service.finishPasskeyAssertion(httpServletRequest.getSession().getId(), credential);
|
||||
return R.success();
|
||||
}
|
||||
|
||||
}
|
||||
38
src/main/java/com/kane/animo/auth/domain/UserCredential.java
Normal file
38
src/main/java/com/kane/animo/auth/domain/UserCredential.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.kane.animo.auth.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户凭证
|
||||
* @author Kane
|
||||
* @since 2025/11/7 16:57
|
||||
*/
|
||||
@Data
|
||||
@TableName("user_credential")
|
||||
public class UserCredential {
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户凭证
|
||||
*/
|
||||
private String credential;
|
||||
/**
|
||||
* 身份标识
|
||||
*/
|
||||
private String identity;
|
||||
/**
|
||||
* 删除标识
|
||||
*/
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.kane.animo.auth.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.kane.animo.auth.domain.UserCredential;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 用户凭证持久层
|
||||
* @author Kane
|
||||
* @since 2025/11/7 17:00
|
||||
*/
|
||||
@Mapper
|
||||
public interface UserCredentialMapper extends BaseMapper<UserCredential> {
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.kane.animo.auth.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.yubico.webauthn.exception.RegistrationFailedException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 通行密钥授权服务
|
||||
*
|
||||
* @author Kane
|
||||
* @since 2025/11/7 17:46
|
||||
*/
|
||||
public interface PasskeyAuthorizationService {
|
||||
/**
|
||||
* 获取通行密钥创建参数
|
||||
*
|
||||
* @return 创建参数
|
||||
*/
|
||||
String startPasskeyRegistration() throws JsonProcessingException;
|
||||
|
||||
/**
|
||||
* 验证通行密钥
|
||||
*
|
||||
* @param credential 凭证
|
||||
*/
|
||||
void finishPasskeyRegistration(String credential) throws IOException, RegistrationFailedException;
|
||||
|
||||
/**
|
||||
* 获取通行密钥验证参数
|
||||
*
|
||||
* @param id 登录id
|
||||
* @return 验证参数
|
||||
*/
|
||||
String startPasskeyAssertion(String id);
|
||||
|
||||
/**
|
||||
* 验证通行密钥
|
||||
*
|
||||
* @param id 登录id
|
||||
* @param credential 凭证
|
||||
*/
|
||||
void finishPasskeyAssertion(String id, String credential);
|
||||
}
|
||||
@ -0,0 +1,160 @@
|
||||
package com.kane.animo.auth.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.kane.animo.auth.domain.User;
|
||||
import com.kane.animo.auth.domain.UserCredential;
|
||||
import com.kane.animo.auth.mapper.UserCredentialMapper;
|
||||
import com.kane.animo.auth.mapper.UserMapper;
|
||||
import com.yubico.webauthn.CredentialRepository;
|
||||
import com.yubico.webauthn.RegisteredCredential;
|
||||
import com.yubico.webauthn.RegistrationResult;
|
||||
import com.yubico.webauthn.data.ByteArray;
|
||||
import com.yubico.webauthn.data.PublicKeyCredentialDescriptor;
|
||||
import com.yubico.webauthn.data.UserIdentity;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 凭证存储
|
||||
* @author Kane
|
||||
* @since 2025/11/7 17:04
|
||||
*/
|
||||
@Service
|
||||
public class CredentialRepositoryImpl implements CredentialRepository {
|
||||
|
||||
@Resource
|
||||
private UserMapper userMapper;
|
||||
|
||||
@Resource
|
||||
private UserCredentialMapper credentialMapper;
|
||||
|
||||
/**
|
||||
* Get the credential IDs of all credentials registered to the user with the given username.
|
||||
*
|
||||
* <p>After a successful registration ceremony, the {@link RegistrationResult#getKeyId()} method
|
||||
* returns a value suitable for inclusion in this set.
|
||||
*
|
||||
* <p>Implementations of this method MUST NOT return null.
|
||||
*
|
||||
* @param username
|
||||
*/
|
||||
@Override
|
||||
public Set<PublicKeyCredentialDescriptor> getCredentialIdsForUsername(String username) {
|
||||
User one = new LambdaQueryChainWrapper<>(userMapper)
|
||||
.eq(User::getUser, username)
|
||||
.one();
|
||||
return new LambdaQueryChainWrapper<>(credentialMapper)
|
||||
.eq(UserCredential::getUserId, one.getId())
|
||||
.list()
|
||||
.stream()
|
||||
.map(UserCredential::getCredential)
|
||||
.map(x -> {
|
||||
RegisteredCredential credential = JSON.parseObject(x, RegisteredCredential.class);
|
||||
return PublicKeyCredentialDescriptor.builder()
|
||||
.id(credential.getCredentialId())
|
||||
.build();
|
||||
}).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user handle corresponding to the given username - the inverse of {@link
|
||||
* #getUsernameForUserHandle(ByteArray)}.
|
||||
*
|
||||
* <p>Used to look up the user handle based on the username, for authentication ceremonies where
|
||||
* the username is already given.
|
||||
*
|
||||
* <p>Implementations of this method MUST NOT return null.
|
||||
*
|
||||
* @param username
|
||||
*/
|
||||
@Override
|
||||
public Optional<ByteArray> getUserHandleForUsername(String username) {
|
||||
User one = new LambdaQueryChainWrapper<>(userMapper)
|
||||
.eq(User::getUser, username)
|
||||
.one();
|
||||
return new LambdaQueryChainWrapper<>(credentialMapper)
|
||||
.eq(UserCredential::getUserId, one.getId())
|
||||
.list()
|
||||
.stream().findAny()
|
||||
.map(x -> JSON.parseObject(x.getIdentity(), UserIdentity.class).getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the username corresponding to the given user handle - the inverse of {@link
|
||||
* #getUserHandleForUsername(String)}.
|
||||
*
|
||||
* <p>Used to look up the username based on the user handle, for username-less authentication
|
||||
* ceremonies.
|
||||
*
|
||||
* <p>Implementations of this method MUST NOT return null.
|
||||
*
|
||||
* @param userHandle
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getUsernameForUserHandle(ByteArray userHandle) {
|
||||
Set<Long> userIds = credentialMapper.selectList(null)
|
||||
.stream().filter(x -> {
|
||||
UserIdentity userIdentity = JSON.parseObject(x.getIdentity(), UserIdentity.class);
|
||||
return userIdentity.getId().equals(userHandle);
|
||||
}).map(UserCredential::getUserId).collect(Collectors.toSet());
|
||||
if (userIds.isEmpty()){
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(new LambdaQueryChainWrapper<>(userMapper)
|
||||
.eq(User::getId, userIds.iterator().next())
|
||||
.one()
|
||||
.getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the public key and stored signature count for the given credential registered to the
|
||||
* given user.
|
||||
*
|
||||
* <p>The returned {@link RegisteredCredential} is not expected to be long-lived. It may be read
|
||||
* directly from a database or assembled from other components.
|
||||
*
|
||||
* <p>Implementations of this method MUST NOT return null.
|
||||
*
|
||||
* @param credentialId
|
||||
* @param userHandle
|
||||
*/
|
||||
@Override
|
||||
public Optional<RegisteredCredential> lookup(ByteArray credentialId, ByteArray userHandle) {
|
||||
List<UserCredential> userCredentials = credentialMapper.selectList(null);
|
||||
for (UserCredential userCredential : userCredentials) {
|
||||
RegisteredCredential credential = JSON.parseObject(userCredential.getCredential(), RegisteredCredential.class);
|
||||
UserIdentity identity = JSON.parseObject(userCredential.getIdentity(), UserIdentity.class);
|
||||
if (credential.getCredentialId().equals(credentialId) && identity.getId().equals(userHandle)){
|
||||
return Optional.of(credential);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up all credentials with the given credential ID, regardless of what user they're
|
||||
* registered to.
|
||||
*
|
||||
* <p>This is used to refuse registration of duplicate credential IDs. Therefore, under normal
|
||||
* circumstances this method should only return zero or one credential (this is an expected
|
||||
* consequence, not an interface requirement).
|
||||
*
|
||||
* <p>Implementations of this method MUST NOT return null.
|
||||
*
|
||||
* @param credentialId
|
||||
*/
|
||||
@Override
|
||||
public Set<RegisteredCredential> lookupAll(ByteArray credentialId) {
|
||||
List<UserCredential> userCredentials = credentialMapper.selectList(null);
|
||||
return userCredentials.stream()
|
||||
.map(x -> JSON.parseObject(x.getCredential(), RegisteredCredential.class))
|
||||
.filter(x -> x.getCredentialId().equals(credentialId))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,104 @@
|
||||
package com.kane.animo.auth.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.kane.animo.auth.domain.User;
|
||||
import com.kane.animo.auth.mapper.UserMapper;
|
||||
import com.kane.animo.auth.service.PasskeyAuthorizationService;
|
||||
import com.kane.animo.util.CacheService;
|
||||
import com.yubico.webauthn.FinishRegistrationOptions;
|
||||
import com.yubico.webauthn.RegistrationResult;
|
||||
import com.yubico.webauthn.RelyingParty;
|
||||
import com.yubico.webauthn.StartRegistrationOptions;
|
||||
import com.yubico.webauthn.data.*;
|
||||
import com.yubico.webauthn.exception.RegistrationFailedException;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 通行密钥授权服务实现
|
||||
* @author Kane
|
||||
* @since 2025/11/7 17:46
|
||||
*/
|
||||
@Service
|
||||
public class PasskeyAuthorizationServiceImpl implements PasskeyAuthorizationService {
|
||||
|
||||
@Resource
|
||||
private RelyingParty relyingParty;
|
||||
|
||||
@Resource
|
||||
private UserMapper userMapper;
|
||||
|
||||
@Resource
|
||||
private CacheService cacheService;
|
||||
|
||||
private static final String PASSKEY_REGISTRATION_KEY = "passkey:registration:";
|
||||
private static final String PASSKEY_ASSERTION_KEY = "passkey:assertion:";
|
||||
|
||||
/**
|
||||
* 获取通行密钥创建参数
|
||||
*
|
||||
* @return 创建参数
|
||||
*/
|
||||
@Override
|
||||
public String startPasskeyRegistration() throws JsonProcessingException {
|
||||
User user = userMapper.selectById(StpUtil.getLoginIdAsLong());
|
||||
PublicKeyCredentialCreationOptions options = relyingParty.startRegistration(StartRegistrationOptions.builder()
|
||||
.user(UserIdentity.builder()
|
||||
.name(user.getUser())
|
||||
.displayName(user.getUser())
|
||||
.id(new ByteArray(user.getId().toString().getBytes()))
|
||||
.build())
|
||||
.authenticatorSelection(AuthenticatorSelectionCriteria.builder()
|
||||
.residentKey(ResidentKeyRequirement.REQUIRED)
|
||||
.build())
|
||||
.build());
|
||||
cacheService.setCache(PASSKEY_REGISTRATION_KEY + user.getId(), options.toJson());
|
||||
return options.toCredentialsCreateJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证通行密钥
|
||||
*
|
||||
* @param credential 凭证
|
||||
*/
|
||||
@Override
|
||||
public void finishPasskeyRegistration(String credential) throws IOException, RegistrationFailedException {
|
||||
User user = userMapper.selectById(StpUtil.getLoginIdAsLong());
|
||||
PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> pkc =
|
||||
PublicKeyCredential.parseRegistrationResponseJson(credential);
|
||||
|
||||
PublicKeyCredentialCreationOptions request =
|
||||
PublicKeyCredentialCreationOptions.fromJson(cacheService.getCache(PASSKEY_REGISTRATION_KEY + user.getId(), String.class));
|
||||
|
||||
RegistrationResult result = relyingParty.finishRegistration(FinishRegistrationOptions.builder()
|
||||
.request(request)
|
||||
.response(pkc)
|
||||
.build());
|
||||
cacheService.removeCache(PASSKEY_REGISTRATION_KEY + user.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通行密钥验证参数
|
||||
*
|
||||
* @param id 登录id
|
||||
* @return 验证参数
|
||||
*/
|
||||
@Override
|
||||
public String startPasskeyAssertion(String id) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证通行密钥
|
||||
*
|
||||
* @param id 登录id
|
||||
* @param credential 凭证
|
||||
*/
|
||||
@Override
|
||||
public void finishPasskeyAssertion(String id, String credential) {
|
||||
|
||||
}
|
||||
}
|
||||
27
src/main/java/com/kane/animo/config/CacheConfigurer.java
Normal file
27
src/main/java/com/kane/animo/config/CacheConfigurer.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.kane.animo.config;
|
||||
|
||||
import org.ehcache.CacheManager;
|
||||
import org.ehcache.config.builders.CacheConfigurationBuilder;
|
||||
import org.ehcache.config.builders.CacheManagerBuilder;
|
||||
import org.ehcache.config.builders.ResourcePoolsBuilder;
|
||||
import org.ehcache.config.units.EntryUnit;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 缓存配置
|
||||
* @author Kane
|
||||
* @since 2025/11/7 18:02
|
||||
*/
|
||||
@Configuration
|
||||
public class CacheConfigurer {
|
||||
@Bean(destroyMethod = "close")
|
||||
public CacheManager init(){
|
||||
return CacheManagerBuilder.newCacheManagerBuilder()
|
||||
.withCache("cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class,
|
||||
String.class,
|
||||
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(1000, EntryUnit.ENTRIES)))
|
||||
.build(true);
|
||||
}
|
||||
|
||||
}
|
||||
36
src/main/java/com/kane/animo/config/PasskeyConfigurer.java
Normal file
36
src/main/java/com/kane/animo/config/PasskeyConfigurer.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.kane.animo.config;
|
||||
|
||||
import com.kane.animo.config.properties.PasskeyProperties;
|
||||
import com.yubico.webauthn.CredentialRepository;
|
||||
import com.yubico.webauthn.RelyingParty;
|
||||
import com.yubico.webauthn.data.RelyingPartyIdentity;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 通行密钥配置
|
||||
* @author Kane
|
||||
* @since 2025/11/7 17:31
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(PasskeyProperties.class)
|
||||
public class PasskeyConfigurer {
|
||||
|
||||
@Resource
|
||||
private CredentialRepository credentialRepository;
|
||||
|
||||
@Bean
|
||||
public RelyingParty relyingParty(PasskeyProperties properties){
|
||||
RelyingPartyIdentity rpIdentity = RelyingPartyIdentity.builder()
|
||||
.id(properties.getId())
|
||||
.name(properties.getName())
|
||||
.build();
|
||||
|
||||
return RelyingParty.builder()
|
||||
.identity(rpIdentity)
|
||||
.credentialRepository(credentialRepository)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.kane.animo.config.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 通行密钥配置参数
|
||||
* @author Kane
|
||||
* @since 2025/11/7 17:36
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "passkey")
|
||||
public class PasskeyProperties {
|
||||
private String id;
|
||||
private String name;
|
||||
}
|
||||
35
src/main/java/com/kane/animo/util/CacheService.java
Normal file
35
src/main/java/com/kane/animo/util/CacheService.java
Normal file
@ -0,0 +1,35 @@
|
||||
package com.kane.animo.util;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.ehcache.Cache;
|
||||
import org.ehcache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 缓存服务
|
||||
* @author Kane
|
||||
* @since 2025/11/7 18:11
|
||||
*/
|
||||
@Service
|
||||
public class CacheService {
|
||||
@Resource
|
||||
private CacheManager manager;
|
||||
|
||||
private Cache<String, String> getBucket(){
|
||||
return manager.getCache("cache", String.class, String.class);
|
||||
}
|
||||
|
||||
public void setCache(String key, Object value){
|
||||
getBucket().put(key, JSON.toJSONString(value));
|
||||
}
|
||||
|
||||
public <T> T getCache(String key, Class<T> clazz){
|
||||
String json = getBucket().get(key);
|
||||
return JSON.parseObject(json, clazz);
|
||||
}
|
||||
|
||||
public void removeCache(String key){
|
||||
getBucket().remove(key);
|
||||
}
|
||||
}
|
||||
3
src/main/resources/application-dev.yml
Normal file
3
src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,3 @@
|
||||
passkey:
|
||||
id: "localhost"
|
||||
name: "Animo"
|
||||
3
src/main/resources/application-prod.yml
Normal file
3
src/main/resources/application-prod.yml
Normal file
@ -0,0 +1,3 @@
|
||||
passkey:
|
||||
id: "animo.alina-dace.info"
|
||||
name: "Animo"
|
||||
@ -2,6 +2,8 @@ server:
|
||||
port: 8080
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
application:
|
||||
name: Animo
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user