79596888

Date: 2025-04-28 16:21:09
Score: 0.5
Natty:
Report link

Rather than using these front dependencies, I used the google and cdn publics librairies, this is not mandatory

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.4.1</version>
</dependency>
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>bootstrap</artifactId>
    <version>4.3.1</version>
</dependency>
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>webjars-locator-core</artifactId>
</dependency>

values in static/index.html

<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css"/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js"></script>

I wrapped the get user code in a getUser() function to refresh the dom

    <script type="text/javascript">
        $.get("/user", function(data) {
            $("#user").html(data.name);
            $(".unauthenticated").hide()
            $(".authenticated").show()
        });
    </script>

To

    var getUser = function() {
                $.get("/user", (data) => {
                    if (data.name) {
                        $("#span-user").html(data.name);
                        $(".unauthenticated").hide();
                        $(".authenticated").show()
                    } else {
                        $(".unauthenticated").show();
                        $(".authenticated").hide()
                    }})
                }
    // call on load and after logout
     getUser();

For the section Making the Home Page Public, you can no longer extend the WebSecurityConfigurerAdapter and override configure(), instead you have to create a SecurityFilterChain bean, in a @Configuration & @EnableWebSecurity class

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) { ...}

for the exception handling with 401 response in the guide, it's not working, and I replaced it

http 
...
.exceptionHandling(e -> e
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))

with this custom endpoint /access/denied and its controller

http
...
.exceptionHandling((exceptionCustomizer) -> 
            exceptionCustomizer
            .accessDeniedPage("/access/denied")

the controller

@RestController
@RequestMapping("/access")
public class AccessController {

    @PostMapping("/denied")
    public ResponseEntity<Map<String, String>> accessDenied() {
        return ResponseEntity
        .badRequest()
        .body(Map.of("access", "denied"));
    }
}

And also add the pattern to requestMatchers() to allow the endpoint and the page to be accessed without login

.requestMatchers("/static/access-**", "/access**" ...).permitAll()

I tested this by commenting the _csrf token in the logout $.post() in the next step of the guide in index.html, the redirection to a custom error page is handled by the frontend (jquery/js here) in index.html

oauth2Login() is deprecated, instead use

http...
.oauth2Login(withDefaults())

In the next section Adding a Logout Endpoint I added a call to delete oauth cookies and invalidate the session, and replaced the Add a Logout Button $.post("/logout") .. in index.html

.logout(logoutCustomizer -> logoutCustomizer
            .invalidateHttpSession(true)
            // .logoutUrl("/logout") // default is /logout
            .logoutSuccessUrl("/") // redirect to homepage after logout
            .deleteCookies("JSESSIONID", "XSRF-TOKEN")
            .permitAll())

and changed http.csrf(c -> c.csrfTokenRepository(..)) to http....csrf(withDefaults()) and added a custom csrf endpoint called by frontend

@RestController
public class CsrfController {
    @GetMapping("/csrf")
    public CsrfToken getCsrf(CsrfToken csrfToken) {
        return csrfToken;
    } 
}

In the next section Adding the CSRF Token in the Client, I used the cdn library instead of the dependency

<script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/3.0.5/js.cookie.min.js"></script>

And replaced the $.ajaxSetup(beforeSend: ) that adds a CSRF cookie before sending with $.post() that calls the /csrf endpoint to get a valid csrf token, and the oauth2 /logout default endpoint, it didn't work otherwise

var logout = function() {
            $.get("/csrf", (data) => {
                var csrfHeader = data.headerName
                var csrfValue = data.token
                $.ajax({
                    url: "/logout",
                    type: 'POST',
                    data: {
                        '_csrf': csrfValue
                    },
                    success: (s) => {
                        $("#span-user").html('');
                        $(".unauthenticated").hide();
                        $(".authenticated").show()
                        getUser() // refresh dom
                    },
                    error: (e) => {
                        if (e.status == 400 && e.responseJSON.access == 'denied') {
                            window.location.href = "/access-denied.html"
                        }
                    }
                })
            })
            return true;
        }

the next section Login with GitHub is to add a google auth, and requires you to configure a client and secret in the google cloud console

in the sub section How to Add a Local User Database I added a small in memory map that contains the users to simulate the described case

In the next section Adding an Error Page for Unauthenticated Users I didn't add the js in Detecting an Authentication Failure in the Client or override the /error endpoint, instead I created a custom static/access-401.html with the message retrieved with js in the url as a query param.

<div class="container text-danger error"></div>
    <script>
        let searchParams = new URLSearchParams(location.search)
        if (searchParams.has('error')) {
            $(".error").html(searchParams.get('error'))
        }
    </script>

In the sub section Adding an Error Message I replaced the failure handler to send a redirect to the 401 page instead of setting an attribute, note that setting the attribute might work but the message cannot be seen as it requires the user to login

http...
.failureHandler((request, response, exception) -> {
  response.sendRedirect("/access-401.html?error=".concat(exception.getMessage()));
})

In the next sub section Generating a 401 in the Server, it uses reactive but I used RestClient as a preference with some changes like the use of a reactive function .attributes(oauth2AuthorizedClient(client)) with .attributes((attributes) -> attributes.put(OAuth2AuthorizedClient.class.getName(), authorizedClient))

or the .bodyToMono() with .toEntity(new ParameterizedTypeReference<List<Map<String, Object>>>(){});

For the last part creating a WebCLient bean I made a basic RestClient without .filter()

@Bean
  public RestClient restClient(RestClient.Builder builder) {
    return builder
      .build();
  }

And here is the link to my github repo with the full project : url

Reasons:
  • Blacklisted phrase (1): here is the link
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: IKeepForgettingAccsMail