Filtro de Segurança Spring com integração OIDC para Casdoor
Casdoor é um IDP de código aberto que suporta OIDC e vários outros protocolos. Neste artigo, veremos como integrar o Casdoor com sua aplicação usando o Filtro de Segurança Spring e OIDC.
Passo 1: Implemente o Casdoor
Primeiro, você precisa implementar o servidor Casdoor. Consulte a documentação oficial para instruções de instalação do servidor. Após a implementação bem-sucedida, certifique-se de que:
- O servidor Casdoor está em execução em http://localhost:8000.
- Você pode ver a página de login do Casdoor em http://localhost:7001.
- Você pode testar a funcionalidade de login fazendo login com as credenciais
admin
e123
.
Após verificar esses passos, siga os passos abaixo para integrar o Casdoor com sua aplicação.
Passo 2: Configure a Aplicação Casdoor
- Crie uma nova aplicação Casdoor ou use uma existente.
- Adicione sua URL de redirecionamento. Você pode encontrar mais informações sobre como obter a URL de redirecionamento na próxima seção.
- Obtenha seu
Certificado
na página de edição de certificado. - Adicione o provedor e outras configurações conforme necessário.
Você pode obter os valores para Nome da Aplicação
, Nome da Organização
, URL de Redirecionamento
, ID do Cliente
, Segredo do Cliente
e Certificado
na página de configurações da aplicação. Usaremos esses valores na próxima etapa.
Passo 3: Configure o Spring Security
Você pode personalizar as configurações dos filtros do Spring Security para processar tokens:
Certifique-se de substituir os valores de configuração pelos da sua própria instância Casdoor, especialmente <Client ID>
e os outros.
server:
port: 8080
casdoor:
endpoint: http://CASDOOR_HOSTNAME:8000
client-id: <Client ID>
client-secret: <Client Secret>
certificate: <Certificate>
organization-name: <Organization Name>
application-name: <Application Name>
redirect-url: http://FRONTEND_HOSTNAME/callback
Para aplicações frontend, o valor padrão de <FRONTEND_HOSTNAME>
é localhost:3000
. Nesta demonstração, a URL de redirecionamento é http://localhost:3000/callback
. Certifique-se de configurar isso na sua aplicação casdoor
.
Passo 4: Configure o Frontend
Você precisa instalar casdoor-js-sdk
e configurar o SDK da seguinte forma:
Instale
casdoor-js-sdk
.npm i casdoor-js-sdk
# or
yarn add casdoor-js-sdkConfigure o
SDK
.import Sdk from "casdoor-js-sdk";
// Serverurl is the URL where spring security is deployed
export const ServerUrl = "http://BACKEND_HOSTNAME:8080";
const sdkConfig = {
serverUrl: "http://CASDOOR_HOSTNAME:8000",
clientId: "<your client id>",
appName: "<your application name>",
organizationName: "<your organization name>",
redirectPath: "/callback",
};
export const CasdoorSDK = new Sdk(sdkConfig);
Passo 5: Configure uma Demonstração
Crie uma aplicação Spring Boot.
Adicione algumas configurações para lidar com JWT.
@EnableWebSecurity
public class SecurityConfig {
private final JwtTokenFilter jwtTokenFilter;
public SecurityConfig(JwtTokenFilter jwtTokenFilter) {
this.jwtTokenFilter = jwtTokenFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// enable CORS and disable CSRF
http = http.cors(corsConfig -> corsConfig
.configurationSource(configurationSource())
).csrf().disable();
// set session management to stateless
http = http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and();
// set permissions on endpoints
http.authorizeHttpRequests(authorize -> authorize
.mvcMatchers("/api/redirect-url", "/api/signin").permitAll()
.mvcMatchers("/api/**").authenticated()
);
// set unauthorized requests exception handler
http = http
.exceptionHandling()
.authenticationEntryPoint(
(request, response, ex) -> ResponseUtils.fail(response, "unauthorized")
)
.and();
// add JWT token filter
http.addFilterBefore(
jwtTokenFilter,
UsernamePasswordAuthenticationFilter.class
);
return http.build();
}
// ...
}
```
Adicione um filtro JWT simples para interceptar requisições que requerem verificação de token.
@Component
public class JwtTokenFilter extends OncePerRequestFilter {
private final CasdoorAuthService casdoorAuthService;
public JwtTokenFilter(CasdoorAuthService casdoorAuthService) {
this.casdoorAuthService = casdoorAuthService;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain)
throws ServletException, IOException {
// get authorization header and validate
final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (!StringUtils.hasText(header) || !header.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
// get jwt token and validate
final String token = header.split(" ")[1].trim();
// get user identity and set it on the spring security context
UserDetails userDetails = null;
try {
CasdoorUser casdoorUser = casdoorAuthService.parseJwtToken(token);
userDetails = new CustomUserDetails(casdoorUser);
} catch (CasdoorAuthException exception) {
logger.error("casdoor auth exception", exception);
chain.doFilter(request, response);
return;
}
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails,
null,
AuthorityUtils.createAuthorityList("ROLE_casdoor")
);
authentication.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
}Quando o usuário acessa a interface que requer autenticação,
JwtTokenFilter
irá obter o token do cabeçalho da requisiçãoAuthorization
e verificar.Defina um
Controller
para lidar quando o usuário faz login no Casdoor. Após o usuário fazer login, ele será redirecionado para o servidor e carregará ocode
e ostate
. O servidor então precisa verificar a identidade do usuário no Casdoor e obter otoken
através desses dois parâmetros.@RestController
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
private final CasdoorAuthService casdoorAuthService;
// ...
@PostMapping("/api/signin")
public Result signin(@RequestParam("code") String code, @RequestParam("state") String state) {
try {
String token = casdoorAuthService.getOAuthToken(code, state);
return Result.success(token);
} catch (CasdoorAuthException exception) {
logger.error("casdoor auth exception", exception);
return Result.failure(exception.getMessage());
}
}
// ...
}
```
Passo 6: Experimente a Demonstração
Você pode acessar a aplicação frontend através do seu navegador. Se você não estiver logado, verá um botão de login. Clique nele, e você será redirecionado para a página de login do Casdoor.
Se você visitar sua página raiz,
Clique no botão Login Casdoor
, e a página redirecionará para a página de login do Casdoor.
Após fazer login, você será redirecionado para /
.