We can use Spring Interceptor feature to authenticate user more efficiently.

Develop User Profile

Add Method into User Service

Add following methods into the UserService.java file under the service/src/main/java/co.dongchen.shop/service directory:

1
2
3
4
5
    public void update(User user, String email) {
        user.setEmail(email);
        BeanHelper.onUpdate(user);
        userMapper.update(user);
    }

Add Attribute into User Controller

Add following atribute into the UserController.java file under the controller/src/main/java/co.dongchen.shop/controller directory:

1
2
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

Add Methods into User Controller

Add following methods into the UserController.java file under the controller/src/main/java/co.dongchen.shop/controller directory:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    @RequestMapping("user/profile")
    public String profile(User user, ModelMap model, HttpServletRequest request) {
        if ("GET".equalsIgnoreCase(request.getMethod())) {
            return "/user/profile";
        }
        userService.update(user, user.getEmail());
        User condition = new User();
        condition.setEmail(user.getEmail());
        List<User> users = userService.queryUserByCondition(condition);
        request.getSession(true).setAttribute(Constants.LOGGED_ON_USER, users.get(0));
        return "redirect:/user/profile?" + ResultMsg.successMsg("Profile Update succeeded!").asUrlParams();
    }

    @RequestMapping("/user/update-password")
    public String updatePassword(User user, ModelMap model) {
        User userAuthenticated = userService.authenticate(user.getEmail(), user.getPassword());
        if (userAuthenticated == null || !user.getConfirmedPassword().equals(user.getNewPassword())) {
            return "redirect:/user/profile?" + ResultMsg.errorMsg("Password incorrect!").asUrlParams();
        }
        User finalUser = new User();
        finalUser.setPassword(bCryptPasswordEncoder.encode(user.getNewPassword()));
        userService.update(finalUser, user.getEmail());
        return "redirect:/user/profile?" + ResultMsg.successMsg("Password Update succeeded!").asUrlParams();
    }

Create Profile Template

  • Right click controller/src/main/resources/templates/user directory: New > File
  • Fill in “profile.ftl”
  • Click “OK” button
img

Copy and paste the following content into profile.ftl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<html lang="en-NZ">
<@common.header/>
<body>
    ${errorMsg!}
    ${successMsg!}
    <h1>Edit Profile</h1>
    <form method="post" action="/user/profile">
        <div>
            <label>First Name:</label>
            <input type="text"  name="firstName" value="${(LOGGED_ON_USER.firstName)!}" required>
        </div>
        <div>
            <label>Last Name:</label>
            <input type="text"  name="lastName" value="${(LOGGED_ON_USER.lastName)!}" required>
        </div>
        <div>
            <label>Email:</label>
            <input type="text"  name="email" value="${(LOGGED_ON_USER.email)!}" required>
        </div>
        <div>
            <label>Introduction:</label>
            <textarea name="introduction">${(LOGGED_ON_USER.introduction)!}</textarea>
        </div>
        <div>
            <button type="submit">Update Profile</button>
        </div>
    </form>
    <h1>Edit Password</h1>
    <form method="post" action="/user/update-password">
        <input type="hidden"  name="email" value="${(LOGGED_ON_USER.email)!}" required>
        <div>
            <label>Current Password:</label>
            <input type="password" name="password" value="${password!}" required>
        </div>
        <div>
            <label>New Password:</label>
            <input type="password" name="newPassword" value="${newPassword!}" required>
        </div>
        <div>
            <label>Confirmed Password:</label>
            <input type="password" name="confirmedPassword" value="${confirmedPassword!}" required>
        </div>
        <div>
            <button type="submit">Update Password</button>
        </div>
    </form>
</body>
<@common.footer/>
</html>

Create Interceptor

  • Right click controller/src/main/java directory: New > Package
  • Fill in “co.dongchen.shop.interceptor”
  • Click “OK” button
    img

Create User Context

  • Right click controller/src/main/java/co.dongchen.shop/interceptor directory: New > Java Class
  • Fill in “UserContext”
  • Click “OK” button
img

Copy and paste the following content into UserContext.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package co.dongchen.shop.interceptor;

import co.dongchen.shop.common.model.User;

public class UserContext {
    private static final ThreadLocal<User> USER_THREAD_LOCAL = new ThreadLocal<>();

    public static void setUserThreadLocal(User user) {
        USER_THREAD_LOCAL.set(user);
    }

    public static void removeUserThreadLocal() {
        USER_THREAD_LOCAL.remove();
    }

    public static User getUserThreadLocal() {
        return USER_THREAD_LOCAL.get();
    }
}

Create Authentication Interceptor

  • Right click controller/src/main/java/co.dongchen.shop/interceptor directory: New > Java Class
  • Fill in “AuthenticationInterceptor”
  • Click “OK” button
img

Copy and paste the following content into AuthenticationInterceptor.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package co.dongchen.shop.interceptor;

import co.dongchen.shop.common.constant.Constants;
import co.dongchen.shop.common.model.User;
import com.google.common.base.Joiner;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Map;

@Component
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(final HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map<String, String[]> map = request.getParameterMap();
        map.forEach((k,v) -> {
            if (k.equals("errorMsg") || k.equals("successMsg") || k.equals("dest")) {
                request.setAttribute(k, Joiner.on(",").join(v));
            }
        });
        String requestURI = request.getRequestURI();
        if (requestURI.startsWith("/static") || requestURI.startsWith("/error")) {
            return true;
        }
        HttpSession session = request.getSession(true);
        User user = (User) session.getAttribute(Constants.LOGGED_ON_USER);
        if (user != null) {
            UserContext.setUserThreadLocal(user);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserContext.removeUserThreadLocal();
    }
}

Create Authentication Action Interceptor

  • Right click controller/src/main/java/co.dongchen.shop/interceptor directory: New > Java Class
  • Fill in “AuthenticationActionInterceptor”
  • Click “OK” button
img

Copy and paste the following content into AuthenticationActionInterceptor.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package co.dongchen.shop.interceptor;

import co.dongchen.shop.common.model.User;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;

@Component
public class AuthenticationActionInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        User user = UserContext.getUserThreadLocal();
        if (user == null) {
            String msg = URLEncoder.encode("Please Log In First!", "utf-8");
            String dest = URLEncoder.encode(request.getRequestURL().toString(), "utf-8");
            if ("GET".equalsIgnoreCase(request.getMethod())) {
                response.sendRedirect("/user/login?errorMsg=" + msg + "&dest=" + dest);
            } else {
                response.sendRedirect("/user/login?errorMsg=" + msg);
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

Create Web MVC Configure

  • Right click controller/src/main/java/co.dongchen.shop/interceptor directory: New > Java Class
  • Fill in “WebMvcConfig”
  • Click “OK” button
img

Copy and paste the following content into WebMvcConfig.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package co.dongchen.shop.interceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private AuthenticationInterceptor authenticationInterceptor;

    @Autowired
    private AuthenticationActionInterceptor authenticationActionInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor).excludePathPatterns("/static").addPathPatterns("/**");
        registry.addInterceptor(authenticationActionInterceptor).addPathPatterns("/user/profile");
    }
}

Verify

Run the App

1
2
// Short Cut for "Run the Program"
Alt + Shift + F10
img

Choose the correspondent option and press enter.

View Login Page in the Browser

1
http://localhost:8080/user/profile
  • Before login, we can’t access to the user profile page:
img
  • We can see the user profile page after logged on:
img
  • We can update the user’s introduction:
img
  • We can also update the user’s login password:
img
  • We will see the following error message if we provided an incorrect current password or if we provided different passwords for new and confirmed passwords:
img
  • We will see the following success message if we provided:
    • the correct current password and;
    • the same password for both new and confirmed passwords.
img

Buy me a coffeeBuy me a coffee