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
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
Create User Context
Right click
controller/src/main/java/co.dongchen.shop/interceptor
directory: New > Java Class
Fill in “UserContext”
Click “OK” button
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
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
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 {
}
}
Right click
controller/src/main/java/co.dongchen.shop/interceptor
directory: New > Java Class
Fill in “WebMvcConfig”
Click “OK” button
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
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:
We can see the user profile page after logged on:
We can update the user’s introduction:
We can also update the user’s login password:
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:
We will see the following success message if we provided:
the correct current password and;
the same password for both new and confirmed passwords.
Buy me a coffee