[JAVA] [Reverse] Spring Security (von Zeit zu Zeit aktualisiert)

Überblick

Bei Verwendung von Spring Security haben wir dies in Form von Reverse Pull zusammengefasst. Die Antwort hier ist nicht die richtige Antwort, es ist nur eine Methode, daher würde ich es begrüßen, wenn Sie darauf verweisen könnten, wenn Sie sich über die Implementierung nicht sicher sind.

Die Referenz wird von Zeit zu Zeit aktualisiert.

Umgebung

Artikel Ausführung
Java 8
Spring Boot 2.2.4

Vorbereitung

Unten finden Sie den minimal erforderlichen Code.

Begrenzen Sie alle Anfragen



@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated();
    }
}

Da wir diesmal keine Verbindung zur Datenbank herstellen, verwenden wir die folgenden Authentifizierungsinformationen.

application.yml


spring:
    security:
        user:
            name: user
            password: pass
            roles: USER

Vorsichtsmaßnahmen

Umgekehrte Auflösung

Gemeinsame Ausgabe

Ich möchte bestimmte Pfade nicht einschränken

SecurityConfig.java



@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/","/login") // 「/」「/Auf "Login" kann ohne Authentifizierung zugegriffen werden
                .permitAll()
                .anyRequest()
                .authenticated();
    }
}

Ich möchte CSRF deaktivieren

CSRF ist standardmäßig aktiviert.

SecurityConfig.java



@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated();
        http.csrf().disable();
    }
}

Ich möchte Anfragen von außerhalb annehmen (Websites mit unterschiedlichen Ursprüngen)

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();
        //Erlaube alle Methoden
        corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
        //Alle Header zulassen
        corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
        //Erlaube alle Ursprünge
        corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);

        UrlBasedCorsConfigurationSource corsSource = new UrlBasedCorsConfigurationSource();
        //Kann für jeden Pfad eingestellt werden. Hier für alle Pfade eingestellt
        corsSource.registerCorsConfiguration("/**", corsConfiguration);

        return corsSource;
    }
}

Ich möchte den Authentifizierungsprozess anpassen

authenticationproviderErstellen Sie eine Implementierungsklasse für.

CustomeAuthenticationProvider.java


@Configuration
public class CustomeAuthenticationProvider implements AuthenticationProvider {

    //Authentifizierungsprozess
    @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("Falsche Anmeldeinformationen");
        }
        return new UsernamePasswordAuthenticationToken(username, password, new ArrayList<>());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

}

securityconfigGeben Sie den oben erstellten Anbieter in an.

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 {
        //Geben Sie den oben erstellten Anbieter an
        auth.authenticationProvider(authenticationProvider);
    }
}

Formularzertifizierung

SecurityConfig.java



@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated();
        http.formLogin();
    }
}

/loginWenn Sie darauf zugreifen, wird der von Spring Security vorbereitete Anmeldebildschirm angezeigt.

Ich möchte meinen eigenen Anmeldebildschirm verwenden

Bereiten Sie den HTML-Code für den Anmeldebildschirm vor.

login.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Einloggen</title>
</head>
<body>
    <form th:action="@{/login}" method="post">
        <input type="text" name="username">
        <input type="password" name="password">
        <button type="submit">Einloggen</button>
    </form>
</body>
</html>

SecurityConfig.java



@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("(A)") //hinzufügen
                .permitAll()         //hinzufügen
                .anyRequest()
                .authenticated()
        http.formLogin()
                .loginPage("(A)");  //hinzufügen
    }
}

Ich möchte die Parameter für die Authentifizierung ändern

Standardmäßig erhalten Sie es mit den Parameternamen `Benutzername``` und Passwort```.

SecurityConfig.java



@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/(A)") //① bestanden
                .permitAll()
                .anyRequest()
                .authenticated()
        http.formLogin()
                .loginPage("/(A)")
                .usernameParameter("(B)")  //hinzufügen
                .passwordParameter("(C)"); //hinzufügen
    }
}

login.html



<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Einloggen</title>
</head>
<body>
    <form th:action="@{/login}" method="post">
        <input type="text" name="(B)">
        <input type="password" name="(C)">
        <button type="submit">Einloggen</button>
    </form>
</body>
</html>

Ich möchte den Bildschirm ändern, der bei erfolgreicher Authentifizierung übergeht

Standardmäßig wechselt es zu "/".

SecurityConfig.java



@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
        http.formLogin()
                .defaultSuccessUrl("/home"); // 「/Übergang zu "Zuhause"
    }
}

Ich möchte mich mit 3 oder mehr Parametern authentifizieren

Normalerweise werden Sie mit zwei Parametern authentifiziert, `Benutzername``` und` Passwort```. Es gibt verschiedene Methoden, aber hier ist die Methode zur Formularauthentifizierung.

Was zu erstellen

Bereiten Sie einen Anmeldebildschirm vor, um die drei Parameter einzugeben.

login.html



<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Einloggen</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">Einloggen</button>
    </form>
</body>
</html>

Erstellen Sie eine Klasse, die das `` `UsernamePasswordAuthenticationToken``` erbt, das die Anmeldeinformationen enthält.

MultiParamAuthenticationToken


public class MultiParamAuthenticationToken extends UsernamePasswordAuthenticationToken {

    private static final long serialVersionUID = 1L;

    private Object tenant; //Zusätzliche Parameter

    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;
    }
}

Erstellen Sie eine Authentifizierungsanbieterklasse.

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);
    }

}

Bereiten Sie eine Filterklasse vor, um den dritten Parameter zu erhalten.

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();

        //Stellen Sie Ihren eigenen Filter ein, ohne formLogin zu verwenden
        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;
    }
}

OAuth-Authentifizierung

Um die OAuth-Authentifizierung durchzuführen, muss der Authentifizierungsanbieter eine Client-ID und ein Geheimnis ausgeben. Hier wird die OAuth-Authentifizierung von Google durchgeführt.

Minimal erforderliche Implementierung

Fügen Sie pom.xml die folgende Abhängigkeit hinzu.

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>

Legen Sie die OAuth-Informationen in application.yml fest.

application.yml


spring:
  security:
    oauth2:
      client:
        registration:
          google:
            clientId: <Kunden ID>
            clientSecret: <Kundengeheimnis>

SpringSecurity.java


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated();

        http.oauth2Login(); //hinzufügen
    }

Ich möchte die Informationen zum Zeitpunkt der Authentifizierung verwenden

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";
    }

oauth2authenticationtokenSie können die Authentifizierungsinformationen mit abrufen.

Erstellen Sie als Nächstes einen Bildschirm für die Anzeige.

index.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Zuhause</title>
</head>
<body>
    <p th:text="${accessToken}"></p>
    <p th:text="${name}"></p>
</body>
</html>

Ich möchte die OAuth-Authentifizierung auf meinem eigenen Anmeldebildschirm durchführen

Erstellen Sie einen Anmeldebildschirm.

login.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Einloggen</title>
</head>
<body>
    <a href="/oauth2/authorization/google">Google-Authentifizierung</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)"); //hinzufügen
    }

Originalzertifizierung

Ich möchte mich bei JSON authentifizieren

usernamepasswordauthenticationfilterErstellen Sie eine Klasse, die von erbt.

JsonAuthenticationFilter.java


public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {

        try {
            //Parameter abrufen
            //Informationen zu Authentifizierungsparametern sind erforderlich.getInputStream()Da es in gespeichert ist, wird es mit Jackson herausgenommen
            Map<String, String> params = new ObjectMapper().readValue(request.getInputStream(),
                    new TypeReference<Map<String, String>>() {});

            //Generierung von Authentifizierungsanforderungsinformationen
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                    params.get("(A)"), params.get("(B)"));

            //Authentifizierung
            return getAuthenticationManager().authenticate(authRequest);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //Prozess, wenn die Authentifizierung erfolgreich ist
    @Override
    protected void successfulAuthentication(HttpServletRequest req,
            HttpServletResponse res,
            FilterChain chain,
            Authentication auth) throws IOException, ServletException {
        //Authentifizierten Benutzer speichern
        //Wenn Sie es nicht speichern, wird es als nicht protokolliert behandelt
        SecurityContextHolder.getContext().setAuthentication(auth);
    }
}

Der Anmeldebildschirm sendet die Anmeldeinformationen über die Ajax-Kommunikation.

login.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Einloggen</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()">Einloggen</button>
    </form>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
        function login() {
            //Authentifizierungsparameter abrufen
            const data = {
                email: document.getElementById('(A)').value,
                password: document.getElementById('(B)').value
            }
            //Authentifizierung
            axios.post('(C)', data)
                .then(res => location.href = "/home") //Wenn die Authentifizierung erfolgreich ist, "/Übergang zu "Zuhause"
        }
    </script>
</body>

</html>

Stellen Sie den oben mit SecuritConfig erstellten Filter ein.

SecurityConfig.java


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("(C)")
                .permitAll()
                .anyRequest()
                .authenticated();

        //Die Ajax-Kommunikation wird ausgeführt. Deaktivieren Sie sie daher
        http.csrf().disable();

        //Stellen Sie den Authentifizierungsfilter von Json ein
        http.addFilter(getJsonAuthenticationFilter());
    }

    private JsonAuthenticationFilter getJsonAuthenticationFilter() throws Exception {
        JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
        //Verwenden Sie die Standardauthentifizierungsmethode
        filter.setAuthenticationManager(authenticationManager());
        //Geben Sie den Pfad an, in dem der Filter ausgeführt werden soll, und die HTTP-Methode
        filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("(C)", "POST"));
        return filter;
    }
}

Erweiterte Version

Ich möchte JWT nach der Authentifizierung zurückgeben

Fügen Sie die JWT-Bibliothek zu pom.xml hinzu.

pom.xml (nur zusätzlich)


<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

Senden Sie die Anmeldeinformationen in JSON und geben Sie die JWT nach Erfolg zurück.

usernamepasswordauthenticationfilterErstellen Sie eine Klasse, die von erbt.

JwtAuthenticationFilter.java


public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {

        try {
            //Parameter abrufen
            //Informationen zu Authentifizierungsparametern sind erforderlich.getInputStream()Da es in gespeichert ist, wird es mit Jackson herausgenommen
            Map<String, String> params = new ObjectMapper().readValue(request.getInputStream(),
                    new TypeReference<Map<String, String>>() {});

            //Generierung von Authentifizierungsanforderungsinformationen
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                    params.get("(A)"), params.get("(B)"));

            //Authentifizierung
            return getAuthenticationManager().authenticate(authRequest);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //Erstellen Sie JWT, wenn die Authentifizierung erfolgreich ist, und legen Sie es im Antwortheader fest.
    @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));

        //JWT-Generation
        String token = JWT.create()
                .withIssuedAt(issuedAt)
                .withNotBefore(notBefore)
                .withExpiresAt(expiresAt)
                .withClaim("(C)", (String)auth.getPrincipal())
                .sign(Algorithm.HMAC512("secret"));

        //Stellen Sie JWT im Autorisierungsheader ein
        res.addHeader("Authorization", "Bearer " + token);
    }
}

onceperrequestfilterErstellen Sie eine Klasse, die jwt überprüft, von dem geerbt wird.

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 ")) {
            //Setzt die Verarbeitung fort, legt jedoch keine Anmeldeinformationen in SecurityContext fest, was zur Rückgabe von 403 führt
            chain.doFilter(req, res);
            return;
        }

        //Wenn es sich um ein Trägerpräfix im Autorisierungsheader handelt
        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();
        //Verwenden Sie die Standardauthentifizierungsmethode
        filter.setAuthenticationManager(authenticationManager());
        //Geben Sie den Pfad an, in dem der Filter ausgeführt werden soll, und die HTTP-Methode
        filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
        return filter;
    }
}

Recommended Posts

[Reverse] Spring Security (von Zeit zu Zeit aktualisiert)
Berühren Sie alle "Anleitungen" des Frühlings (von Zeit zu Zeit aktualisiert)
Memorandum Poem (von Zeit zu Zeit aktualisiert)
SpringBoot nützliche Websitesammlung (von Zeit zu Zeit aktualisiert)
[Von Zeit zu Zeit aktualisiert] Links, die verschuldet sind
Einführung in die Programmierung für Studenten (von Zeit zu Zeit aktualisiert)
[Von Zeit zu Zeit aktualisiert] Ruby on Rails Praktische Methode
[Eclipse] Zusammenfassung der Umgebungseinstellungen * Von Zeit zu Zeit aktualisiert
Versuchen Sie Spring Boot von 0 bis 100.
[Persönliches Memo] Häufig verwendete Java-Grammatik, die von Zeit zu Zeit aktualisiert wird
Persönlich empfohlene Intellij IDEA-Grundeinstellungen (von Zeit zu Zeit aktualisiert)
Rüsten Sie den Federstiefel von der 1.5-Serie auf die 2.0-Serie auf
Zusammenfassung der Forschungsergebnisse zur Objektorientierung [Von Zeit zu Zeit aktualisiert]
Konvertieren Sie von der Java-UTC-Zeit in die JST-Zeit
Die Geschichte des Übergangs von Spring Boot 1.5 zu 2.1
Änderungen bei der Migration von Spring Boot 1.5 auf Spring Boot 2.0
Übergang von Struts2 zu Spring MVC (Controller)
Änderungen bei der Migration von Spring Boot 2.0 zu Spring Boot 2.2
Ich habe versucht, die Grammatik von R und Java zu übersetzen [Von Zeit zu Zeit aktualisiert]
Punkte, auf die ich beim Erstellen einer Android-App gestoßen bin [Von Zeit zu Zeit aktualisiert]
Git-Befehl, auf den neue Ingenieure zurückblicken sollten [Von Zeit zu Zeit aktualisiert]
Holen Sie sich Enum, indem Sie sich vom Inhalt zurückziehen
[Einführung in Spring Boot] Authentifizierungsfunktion mit Spring Security
Spring Boot - So stellen Sie das Sitzungszeitlimit ein
So stellen Sie auf einem virtuellen Server eine Verbindung von Spring zu MySQL her (ungelöst)
Push-Übermittlung von der Spring-Anwendung an Firebase Cloud Messaging
Versuchen Sie, mit Keycloak mit Spring Security SAML (Spring 5) zu arbeiten.
Neuer Mitarbeiter hat versucht, mit Spring Security eine Authentifizierungs- / Autorisierungsfunktion von Grund auf neu zu erstellen