Lors de l'utilisation de Spring Security, nous l'avons résumé sous la forme de reverse pull. La réponse ici n'est pas la bonne réponse, ce n'est qu'une méthode, donc j'apprécierais que vous puissiez vous y référer lorsque vous n'êtes pas sûr de la mise en œuvre.
La référence sera mise à jour de temps à autre.
article | version |
---|---|
Java | 8 |
Spring Boot | 2.2.4 |
Vous trouverez ci-dessous le code minimum requis.
Limiter toutes les demandes
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
}
}
Puisque nous ne nous connecterons pas à la base de données cette fois, nous utiliserons les informations d'authentification suivantes.
application.yml
spring:
security:
user:
name: user
password: pass
roles: USER
@ Controller '') sera omise, veuillez donc la créer comme il convient.SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/login") // 「/」「/"login" est accessible sans authentification
.permitAll()
.anyRequest()
.authenticated();
}
}
CSRF est activé par défaut.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.csrf().disable();
}
}
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.cors().configurationSource(getCorsConfigurationSource());
}
private CorsConfigurationSource getCorsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
//Autoriser toutes les méthodes
corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
//Autoriser tous les en-têtes
corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
//Autoriser toutes les origines
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
UrlBasedCorsConfigurationSource corsSource = new UrlBasedCorsConfigurationSource();
//Peut être défini pour chaque chemin. Ici défini pour tous les chemins
corsSource.registerCorsConfiguration("/**", corsConfiguration);
return corsSource;
}
}
authenticationprovider
Créez une classe d'implémentation pour.
CustomeAuthenticationProvider.java
@Configuration
public class CustomeAuthenticationProvider implements AuthenticationProvider {
//Processus d'authentification
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
if (!"user".equals(username) || !"password".equals(password)) {
throw new BadCredentialsException("Informations de connexion incorrectes");
}
return new UsernamePasswordAuthenticationToken(username, password, new ArrayList<>());
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
securityconfig
Spécifiez le fournisseur créé ci-dessus dans.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomeAuthenticationProvider authenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.formLogin();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//Spécifiez le fournisseur créé ci-dessus
auth.authenticationProvider(authenticationProvider);
}
}
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.formLogin();
}
}
/login
Lorsque vous y accédez, l'écran de connexion préparé par spring security s'affiche.
Préparez le HTML pour l'écran de connexion.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>S'identifier</title>
</head>
<body>
<form th:action="@{/login}" method="post">
<input type="text" name="username">
<input type="password" name="password">
<button type="submit">S'identifier</button>
</form>
</body>
</html>
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("(A)") //ajouter à
.permitAll() //ajouter à
.anyRequest()
.authenticated()
http.formLogin()
.loginPage("(A)"); //ajouter à
}
}
Par défaut, vous l'obtenez avec les noms de paramètres username
et `` `password```.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/(A)") //① passer
.permitAll()
.anyRequest()
.authenticated()
http.formLogin()
.loginPage("/(A)")
.usernameParameter("(B)") //ajouter à
.passwordParameter("(C)"); //ajouter à
}
}
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>S'identifier</title>
</head>
<body>
<form th:action="@{/login}" method="post">
<input type="text" name="(B)">
<input type="password" name="(C)">
<button type="submit">S'identifier</button>
</form>
</body>
</html>
Par défaut, il passe à "/".
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
http.formLogin()
.defaultSuccessUrl("/home"); // 「/Transition vers la «maison»
}
}
Normalement, vous êtes authentifié avec deux paramètres, username
et `` `password```.
Il existe plusieurs méthodes, mais voici la méthode d'authentification par formulaire.
Préparez un écran de connexion pour entrer les trois paramètres.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>S'identifier</title>
</head>
<body>
<form th:action="@{/login}" method="post">
<input type="text" name="(A)">
<input type="text" name="username">
<input type="password" name="password">
<button type="submit">S'identifier</button>
</form>
</body>
</html>
Créez une classe qui hérite de UsernamePasswordAuthenticationToken
qui contient les informations d'identification.
MultiParamAuthenticationToken
public class MultiParamAuthenticationToken extends UsernamePasswordAuthenticationToken {
private static final long serialVersionUID = 1L;
private Object tenant; //Paramètres supplémentaires
public MultiParamAuthenticationToken(Object principal, Object credentials, Object tenant) {
super(principal, credentials, Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
this.tenant = tenant;
}
public Object getTenant() {
return this.tenant;
}
}
Créez une classe de fournisseur d'authentification.
MultiParamAuthenticationProvider
@Configuration
public class MultiParamAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
String tenant = null;
if (authentication instanceof MultiParamAuthenticationToken) {
tenant = (String) ((MultiParamAuthenticationToken) authentication).getTenant();
}
if (!"user".equals(username) || !"pass".equals(password) || !"multi".equals(tenant)) {
throw new BadCredentialsException("aaa");
}
return new MultiParamAuthenticationToken(username, password, tenant);
}
@Override
public boolean supports(Class<?> authentication) {
return MultiParamAuthenticationToken.class.isAssignableFrom(authentication);
}
}
Préparez une classe de filtre pour obtenir le troisième paramètre.
MultiParamAuthenticationFilter
public class MultiParamAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
String username = obtainUsername(request);
String password = obtainPassword(request);
String tenant = obtainTenant(request);
MultiParamAuthenticationToken authRequest = new MultiParamAuthenticationToken(
username, password, tenant);
return getAuthenticationManager().authenticate(authRequest);
}
private String obtainTenant(HttpServletRequest request) {
return (String) request.getParameter("tenant");
}
}
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MultiParamAuthenticationProvider authenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login")
.permitAll()
.anyRequest()
.authenticated();
//Définissez votre propre filtre sans utiliser formLogin
http.addFilter(getMultiParamAuthenticationFilter());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
private MultiParamAuthenticationFilter getMultiParamAuthenticationFilter() throws Exception {
MultiParamAuthenticationFilter filter = new MultiParamAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager());
return filter;
}
}
Pour effectuer l'authentification OAuth, il est nécessaire que le fournisseur d'authentification émette un ID client et un secret. Ici, l'authentification OAuth est effectuée par Google.
Ajoutez la dépendance suivante à pom.xml.
pom.xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
Définissez les informations OAuth dans application.yml.
application.yml
spring:
security:
oauth2:
client:
registration:
google:
clientId: <identité du client>
clientSecret: <Secret du client>
SpringSecurity.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.oauth2Login(); //ajouter à
}
LoginController.java
@Controller
public class LoginController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@GetMapping
public String index(OAuth2AuthenticationToken authentication, Model model) {
OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient(
authentication.getAuthorizedClientRegistrationId(),
authentication.getName());
model.addAttribute("name", authorizedClient.getPrincipalName());
model.addAttribute("accessToken", authorizedClient.getAccessToken().getTokenValue());
return "index";
}
oauth2authenticationtoken
Vous pouvez obtenir les informations d'authentification avec.
Ensuite, créez un écran pour l'affichage.
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>domicile</title>
</head>
<body>
<p th:text="${accessToken}"></p>
<p th:text="${name}"></p>
</body>
</html>
Créez un écran de connexion.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>S'identifier</title>
</head>
<body>
<a href="/oauth2/authorization/google">Authentification Google</a>
</body>
</html>
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("(A)")
.permitAll()
.anyRequest()
.authenticated();
http.oauth2Login().loginPage("(A)"); //ajouter à
}
usernamepasswordauthenticationfilter
Créez une classe qui hérite de.
JsonAuthenticationFilter.java
public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
try {
//Obtenir les paramètres
//Les informations de paramètre d'authentification sont demandées.getInputStream()Comme il est stocké, il est retiré à l'aide de Jackson
Map<String, String> params = new ObjectMapper().readValue(request.getInputStream(),
new TypeReference<Map<String, String>>() {});
//Génération d'informations de demande d'authentification
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
params.get("(A)"), params.get("(B)"));
//Authentification
return getAuthenticationManager().authenticate(authRequest);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//Traiter lorsque l'authentification est réussie
@Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth) throws IOException, ServletException {
//Enregistrer l'utilisateur authentifié
//Si vous ne l'enregistrez pas, il sera traité comme non connecté
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
L'écran de connexion enverra les informations d'identification via la communication Ajax.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>S'identifier</title>
</head>
<body>
<form>
<input type="text" id="(A)" name="(A)">
<input type="password" id="(B)" name="(B)">
<button type="button" id="btnLogin" onclick="login()">S'identifier</button>
</form>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
function login() {
//Obtenir les paramètres d'authentification
const data = {
email: document.getElementById('(A)').value,
password: document.getElementById('(B)').value
}
//Authentification
axios.post('(C)', data)
.then(res => location.href = "/home") //Lorsque l'authentification est réussie, "/Transition vers la «maison»
}
</script>
</body>
</html>
Définissez le filtre créé ci-dessus avec SecuritConfig.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("(C)")
.permitAll()
.anyRequest()
.authenticated();
//La communication Ajax est effectuée, alors désactivez-la
http.csrf().disable();
//Définir le filtre d'authentification par Json
http.addFilter(getJsonAuthenticationFilter());
}
private JsonAuthenticationFilter getJsonAuthenticationFilter() throws Exception {
JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
//Utiliser la méthode d'authentification par défaut
filter.setAuthenticationManager(authenticationManager());
//Spécifiez le chemin où le filtre sera exécuté et la méthode HTTP
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("(C)", "POST"));
return filter;
}
}
Ajoutez la bibliothèque JWT à pom.xml.
pom.xml (supplémentaire uniquement)
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
Envoyez les informations d'identification dans JSON et renvoyez le JWT après le succès.
usernamepasswordauthenticationfilter
Créez une classe qui hérite de.
JwtAuthenticationFilter.java
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
try {
//Obtenir les paramètres
//Les informations de paramètre d'authentification sont demandées.getInputStream()Comme il est stocké, il est retiré à l'aide de Jackson
Map<String, String> params = new ObjectMapper().readValue(request.getInputStream(),
new TypeReference<Map<String, String>>() {});
//Génération d'informations de demande d'authentification
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
params.get("(A)"), params.get("(B)"));
//Authentification
return getAuthenticationManager().authenticate(authRequest);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//Créez JWT lorsque l'authentification a réussi et définissez-le dans l'en-tête de réponse.
@Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth) throws IOException, ServletException {
Date issuedAt = new Date();
Date notBefore = new Date(issuedAt.getTime());
Date expiresAt = new Date(issuedAt.getTime() + TimeUnit.MINUTES.toMillis(100L));
//Génération JWT
String token = JWT.create()
.withIssuedAt(issuedAt)
.withNotBefore(notBefore)
.withExpiresAt(expiresAt)
.withClaim("(C)", (String)auth.getPrincipal())
.sign(Algorithm.HMAC512("secret"));
//Définir JWT dans l'en-tête d'autorisation
res.addHeader("Authorization", "Bearer " + token);
}
}
onceperrequestfilter
Créez une classe qui valide jwt qui hérite de.
JwtAuthenticationFilter.java
public class JwtAuthorizationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws ServletException, IOException {
String header = req.getHeader("Authorization");
if (header == null || !header.startsWith("Bearer ")) {
//Continue le traitement, mais ne définit pas les informations d'identification dans SecurityContext, ce qui entraîne le renvoi de 403
chain.doFilter(req, res);
return;
}
//S'il s'agit d'un préfixe de support dans l'en-tête d'autorisation
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
if (Objects.isNull(authentication)) {
chain.doFilter(req, res);
return;
}
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return null;
}
token = token.substring("Bearer ".length());
if (Objects.isNull(token) || token.length() == 0) {
return null;
}
JWTVerifier verifier = JWT.require(Algorithm.HMAC512("secret")).build();
try {
DecodedJWT jwt = verifier.verify(token);
return new UsernamePasswordAuthenticationToken(
jwt.getClaim("(C)").asString(), null,
null);
} catch (JWTDecodeException e) {
return null;
}
}
}
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login")
.permitAll()
.anyRequest()
.authenticated();
http.csrf().disable();
http.addFilter(getJsonAuthenticationFilter());
}
private JsonAuthenticationFilter getJsonAuthenticationFilter() throws Exception {
JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
//Utiliser la méthode d'authentification par défaut
filter.setAuthenticationManager(authenticationManager());
//Spécifiez le chemin où le filtre sera exécuté et la méthode HTTP
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
return filter;
}
}
Recommended Posts