10件の記事を読んだ後、運が悪くて2時間以上苦労しました。
カスタムフィルタを使用して、DBと@Securedアノテーションのロールに基づいてステートレスな認証を実行したいと考えています。Springブート - カスタムフィルタ/ステートレス認証と@Secured注釈
まず、データベースで識別されている私のアカウントの例「6c1bb23e-e24c-41a5-8f12-72d3db0a6979」から始めましょう。
DBから取り出した文字列ロール: 'FREE_USER_ROLE'があります。
マイフィルタ:
public class ApiKeyAuthFilter extends OncePerRequestFilter {
private final AccountService accountService;
private final GlobalExceptionsAdvice exceptionAdvice;
private static final String API_KEY_HEADER_FIELD = "X-AUTH-KEY";
public static final List<String> NON_AUTH_END_POINTS
= Collections.unmodifiableList(Arrays.asList("/Accounts", "/Accounts/Login"));
AntPathMatcher pathMatcher = new AntPathMatcher();
public ApiKeyAuthFilter(AccountService accountService, GlobalExceptionsAdvice exceptionAdvice) {
this.accountService = accountService;
this.exceptionAdvice = exceptionAdvice;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain fc) throws ServletException, IOException {
Optional authKey = Optional.ofNullable(request.getHeader(API_KEY_HEADER_FIELD));
if (!authKey.isPresent()) {
sendForbiddenErrorMessage(response);
} else {
try {
AccountDTO account = accountService.findByApiKey(authKey.get().toString());
Set<GrantedAuthority> roles = new HashSet();
account.getRoles().forEach((singleRole) -> roles.add(new SimpleGrantedAuthority(singleRole.getName())));
Authentication accountAuth = new UsernamePasswordAuthenticationToken(account.getEmail(), account.getApiKey(),
roles);
SecurityContextHolder.getContext().setAuthentication(accountAuth);
SecurityContextHolder.getContext().getAuthentication().getAuthorities().forEach((role) -> {
System.out.println(role.getAuthority());
});
fc.doFilter(request, response);
} catch (ElementDoesNotExistException ex) {
//TODO: Add logging that user tried to falsy authenticate
sendForbiddenErrorMessage(response);
}
}
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return NON_AUTH_END_POINTS.stream().anyMatch(p -> {
return pathMatcher.match(p, request.getServletPath())
&& request.getMethod().equals("POST");
});
}
private void sendForbiddenErrorMessage(HttpServletResponse resp) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ErrorDetail error = exceptionAdvice.handleAccessDeniedException();
resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
resp.setContentType("application/json");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().write(mapper.writeValueAsString(error));
}
あなたは、私が提供するAPIキーを取得するために、X-AUTH-KEYヘッダを使用しています見ることができるように、そして、私はそのキーに基づいてデータベースから情報を取得し、SecurityContextHolderにappropiate役割を割り当てます。その時点まで、すべてが機能します。私はpoper apiKeyを送信しています、DBは 'FREE_USER_ROLE'を返します。
My @Configurationアノテーションクラス。 (私は何かがここで間違っているが、私は何を言うことができない賭ける):
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class ApiKeySecurityConfiguration extends WebSecurityConfigurerAdapter {
AccountService accountService;
GlobalExceptionsAdvice exceptionAdvice;
@Autowired
public ApiKeySecurityConfiguration(AccountService accountService, GlobalExceptionsAdvice exceptionAdvice) {
this.accountService = accountService;
this.exceptionAdvice = exceptionAdvice;
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.csrf().disable();
httpSecurity.authorizeRequests().anyRequest().authenticated();
httpSecurity.addFilterBefore(new ApiKeyAuthFilter(accountService, exceptionAdvice), UsernamePasswordAuthenticationFilter.class);
}
}
パズルの最後のピース - @Securedを使用してコントローラ:
@RestController
@RequestMapping("/Accounts")
public class AccountsResource {
@Secured({"FREE_USER_ROLE"})
@PutMapping()
public boolean testMethod() {
return true;
}
}
私は「FREE_USER_ROLE」の両方で試してみましたし、 'ROLE_FREE_USER_ROLE'。 403禁止されるたびに。