javascript - Spring Boot / Thymeleaf - Javascript 请求和 X.509 Auth 的身份验证困难
问题描述
我有一个配置为使用 .x509 证书身份验证的 Spring Boot Web 应用程序。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests().antMatchers("/h2-console/**", "/css/**", "/image/**", "/js/**").permitAll()
.and().authorizeRequests().antMatchers("/**").authenticated().and().x509()
.userDetailsService(userDetailsService).subjectPrincipalRegex("CN=(.*?),");
}
}
用户详情服务:
@Service
public class AppUserDetailsService implements UserDetailsService {
@Autowired
private AppUserRepo userRepo;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
var userVal = userRepo.getUser(username);
if (!userVal.isPresent()) {
throw new UsernameNotFoundException("No user with name: " + username);
}
var user = userVal.get();
return new User(user.getUsername(), "",
user.getRoles().stream().map(r -> new SimpleGrantedAuthority(r)).collect(Collectors.toList()));
}
}
我的应用程序大部分时间都在工作;也就是说,我可以使用此设置访问需要授权的完整页面。当我尝试使用 JavaScript/TypeScript 加载片段时,就会出现问题。当我单击触发 JS 调用的按钮时,我收到以下错误:
{"timestamp":"2019-09-17T14:08:44.019+0000","status":403,"error":"Forbidden","message":"Forbidden","path":"/employee/search"}
JS/TS 片段
function loadEmployees() {
const container = document.getElementById("resultPanel");
const url = "employee/search";
fetch(url, {
method: "POST",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(buildBody())
})
.then(res => res.text())
.then(res => container.innerHTML = res);
}
插入片段的模板:
<div id="page" class="container">
<h1>Employee Search</h1>
<div class="clearfix">
<div class='form-row my-3'>
<label for="reqType">Search Type: </label>
<select class="form-control" name="reqType" id="reqType">
<option>Select</option>
<option value=1>SSN</option>
<option value=2>Name</option>
</select>
</div>
/// Code omitted for brevity
<button class="btn btn-primary float-right" id="searchBtn">Search</button>
</div>
片段本身:
<div th:fragment="results-list">
<div class="row d-md-flex flex-header d-none">
<div class="col-md-4">
Name
</div>
<div class="col-md-2">
Loc.
</div>
<div class="col-md-2">
DB
</div>
<div class="col-md-1">
</div>
</div>
<div class="row d-flex" th:each="emp : ${employees}">
<div class="col-md-4">
<span class="font-weight-bold d-inline d-md-none pr-1">Name: </span>
<span th:text="${emp.lastName} + ', ' + ${emp.firstName} + ' ' + ${emp.middleName}"></span>
</div>
<div class=" col-md-2">
<span class="font-weight-bold d-inline d-md-none pr-1">Loc.: </span>
<span th:text="${emp.location}"></span>
</div>
<div class="col-md-2">
<span class="font-weight-bold d-inline d-md-none pr-1">DB: </span>
<span th:text="${emp.dbName}"></span>
</div>
<div class="col-md-1">
<span class="font-weight-bold d-inline d-md-none pr-1">Edit: </span>
<a th:href="@{'/employee/' + ${emp.id}}">View <i class="fas fa-edit"></i></a>
</div>
</div>
</div>
<hr />
<h2 class="mt-1">Results</h2>
<div id="resultPanel" class="mt-4">
</div>
</div>
..以及加载片段的控制器:
@Controller
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService empService;
@PostMapping("/search")
public String searchByName(@RequestBody SearchDTO dto, Model model) {
model.addAttribute("employees", empService.searchEmployees(dto));
return "fragments/results-list";
}
请注意,我意识到 JavaScript 和 Java 是非常不同的语言;鉴于我不确定是否必须在客户端或服务器端执行更改,因此我将两个标签都包括在内。如果您认为这样不合适,请随意删除一个。
非常感谢。
解决方案
我遇到了同样的问题,发现我需要在我的开放资源之前指定我的安全资源。
因此,您可能会在以下方面获得更好的运气:
httpSecurity
.csrf().disable()
.authorizeRequests().antMatchers("/**").authenticated().and().x509()
.userDetailsService(userDetailsService).subjectPrincipalRegex("CN=(.*?),")
.and()
.authorizeRequests().antMatchers("/h2-console/**", "/css/**", "/image/**", "/js/**").permitAll()
;
请参阅此处的文档。
根据反馈进行编辑,使其成为编译器友好的代码示例。
编辑 #2 - 添加 .csrf().disable()。我必须自己这样做才能让 REST 工作,并且看到其他人也这样做。
推荐阅读
- php - Laravel 调用 app 动作 VS 直接调用类对象
- javascript - 在Javascript中将类分配给数组
- c# - 解析 html 并选择具有第二个跨度的第一个表
- powershell - 如何正确获取变量名称并将其导入到 powershell 的任务计划中?
- python - “'For' 是保留关键字。” 机器人框架中的错误(RIDE 工具)
- c# - Azure 上的静态文件
- javascript - React 组件中的按钮单击显示/隐藏
- c# - 文本框数组不会在 userControl WINdows 窗体中更新
- snowflake-cloud-data-platform - 在执行之前预测雪花查询的成本
- c# - 无法保存 png 图像数组:“GDI+ 中的一般错误”