我有一个用 Java Spring Boot 编写的无状态 REST 服务的后端。
1- 其中一项服务是“/登录”。它从我自己的网络表单(不是 Shibboleth 生成的表单)接收用户名和密码。在此服务调用中,我想联系 Shibboleth(使用 OAuth2 或 SAML 或其他方式)来验证该用户并获取令牌。这应该同步完成,因为服务必须向调用者返回“true”或“false”。不允许重定向:要么 true 要么 false。
2- 此令牌将包含在发送回前端的响应中,并将存储在前端中。它将在以下对其他 REST 服务(/Login 除外)的调用中重新发送回后端。这些其他调用必须通过向 Shibboleth 发送令牌来联系 Shibboleth。 Shibboleth 必须返回有关用户的信息,如果令牌不正确,则返回错误。
如何手动实现第 1 点和第 2 点,即不使用 Spring Security?只是纯Java,也许还有其他第三方库。
如果您不想使用 Spring Security,您应该将令牌保存在 Redis 或包含用户 ID 及其令牌的表中。之后你应该编写过滤器。推荐使用aspect或者spring-Aop.
在每个请求中,该请求首先到达您的方面,从前端获取用户 ID 和令牌,然后从 Redis 或您的数据库获取该用户 ID 的令牌,并将它们相互比较,如果正确,您的请求将继续,如果是不正确会抛出异常。
下面有一个示例 Aop 代码
package com.dpco.aop;
import com.dpco.business.exception.CustomException;
import com.dpco.logger.Logger4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
@Aspect
@Configuration
public class LoggerAspect {
@Autowired
private Logger4j logger4j;
@Pointcut("execution(* com.dpco.controller.*.*(..)) && @annotation(requestMapping)")
public void controller(RequestMapping requestMapping){
}
@Around("controller(requestMapping)")
public Object around(ProceedingJoinPoint joinPoint , RequestMapping requestMapping) throws Throwable {
Object[] obj = joinPoint.getArgs();
File file = new File("log.txt");
Object object = null;
try {
if (file.createNewFile()) {
FileWriter fileWriter = new FileWriter(file);
fileWriter.write("\n\n-----------------------------------------this is the logger of project , you can see the methods that calls and information of them in here------------------------------------\n\n");
fileWriter.close();
}
FileWriter fileWriter = new FileWriter(file, true);
Date first = new Date();
fileWriter.write("\n---------------------------------------" + joinPoint.getSignature().getName() + "-------------------------------------------\n");
fileWriter.write("path is : " + requestMapping.path()[0] + "\n");
fileWriter.write("the method of request is :" + requestMapping.method()[0] + "\n");
StringBuilder builder = new StringBuilder();
for (Object arg : obj) {
builder.append(arg.toString() + ",");
}
if(builder.length() != 0) {
builder.deleteCharAt(builder.indexOf(builder.toString()));
}
fileWriter.write("the arguments of this method is : " + builder.toString() + "\n");
object = joinPoint.proceed();
Date second = new Date();
fileWriter.write("the milli seconds that left : " + String.valueOf(second.getTime() - first.getTime()));
fileWriter.close();
} catch (IOException e) {
logger4j.getLogger(e);
throw new CustomException("hello", HttpStatus.MULTI_STATUS);
}
return object;
}
}
此方面包含每次调用休息控制器之前的日志
您可以根据您的需要进行更改。
我认为根据您的需求这是最好的方法