How do I implement the applet to use custom annotations to get the current logged in user???

Posted by webdevelope on Tue, 19 Nov 2019 21:41:38 +0100

Business Scenarios

  • In our program code, many interface calls are limited and need to be logged in to operate. This article mainly uses definition annotations to intercept login validation when calling an interface.

Custom Notes

/**
 * Use this comment on the Controller method parameter, which injects the current login object into the map
 *
 * @Author Lin Bizhao
 * @Date 2019/11/12 17:29
 */

@Target({ElementType.PARAMETER, ElementType.METHOD})    //You can modify parameters or methods
@Retention(RetentionPolicy.RUNTIME)                     //Runtime Effective
public @interface LoginUser {
}

Customize a handler method parameter parser (class) and implement HandlerMethodArgumentResolver

/**
 * In general, the current login user is required in the controller method, so we can customize Handler MethodArgumentResolver (handler method parameter parser)
 * To get the current logged in user, with the @LoginUser annotated method parameter, indicating injection of the current logged in user
 *
 * @Author Lin Bizhao
 * @Date 2019/11/12 18:56
 */
public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    private static final String LOGIN_TOKEN_KEY = "X-HomeShop-Login-Token";

    /**
     * Used to determine if a parameter in the Controller layer satisfies a condition, resolveArgument method is executed if it satisfies a condition, or skipped if it does not
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //Determine if the parameter type is an Integer type and if there are annotation @LoginUser annotation modifiers
        return parameter.getParameterType().isAssignableFrom(Integer.class) && parameter.hasParameterAnnotation(LoginUser.class);
    }

    /**
     * The supportsParameter method is called only if it returns true.For some business, return Object is controller
     * The parameter object on the method, that is, the parameter that assigns the return value to the Controller
     */
    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer container,
                                  NativeWebRequest request,
                                  WebDataBinderFactory factory) throws Exception {
        //Get parameter information from request header
        String token = request.getHeader(LOGIN_TOKEN_KEY);
        if (token == null || token.isEmpty()){
            return null;
        }
        //UserTokenManager.getUserId(token) actually returns userId
        return UserTokenManager.getUserId(token);
    }
}

UserTokenManager

In fact, UserTokenManager.getUserId(token) returns our userId, and the resolveArgement method gives us the Controller's parameter userId

/**
 * User token maintenance class
 *
 * @Author Lin Bizhao
 * @Date 2019/11/11 19:51
 */
public class UserTokenManager {

    public static String generateToken(Integer id) {
        JwtHelper jwtHelper = new JwtHelper();
        return jwtHelper.createToken(id);
    }
    public static Integer getUserId(String token) {
        JwtHelper jwtHelper = new JwtHelper();
        Integer userId = jwtHelper.verifyTokenAndGetUserId(token);
        if(userId == null || userId == 0){
            return null;
        }
        return userId;
    }
}

Custom configuration class handles the Relver above to the Spring container

/**
 * @Author Lin Bizhao
 * @Date 2019/11/12 19:09
 */
@Configuration
public class WxWebMvcConfiguration implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new LoginUserHandlerMethodArgumentResolver());
    }
}

Controller uses

When an interface call requires a login user identity, you need to verify that the current user is in the login state, for example, to obtain user information, you must be in the login state, so you can use the @LoginUser annotation to verify:

/**
 * Login Authorization API
 *
 * @Author Lin Bizhao
 * @Date 2019/9/22 10:19
 */
@Api(tags = "Login Authorization API")
@Slf4j
@RestController
@RequestMapping("/api/auth")
public class ApiAuthController extends ApiBaseController {
     /**
     * Get user information
     */
    @GetMapping("/info")
    @ApiOperation(value = "Get User Information Interface")
    public Object getUserInfo(@LoginUser Integer userId){
        if (userId==null){
            return ServerResponse.createByErrorCodeMessage(ResponseCodeEnum.NEED_LOGIN.getCode(),"Please login first");
        }
        User user = userRepository.findUserByUserId(userId);
        Map<Object,Object> userData = new HashMap<>();
        userData.put("nickName", user.getNickname());
        userData.put("avatar", user.getAvatar());
        userData.put("gender", user.getGender());
        userData.put("mobile", user.getMobile());

        return ServerResponse.createBySuccess(userData);
    }

}

Use Session to save current user information

I think the custom login authentication comment @LoginUser is the same authentication mechanism as session management user login information in our web domain. After user login, the user information is saved in our session. When the interface is called, it needs to verify whether the user exists in session or not. If it does not exist, it needs to force login. Next, see the code:

UserController

/**
 * @Author Lin Bizhao
 * @Date 2019/6/16 16:34
 */

@Slf4j
@Controller
@RequestMapping("/user/")
public class UserController {

    @Autowired
    UserService userService;

    /**
     * User logs in and saves information in session
     *
     * @param username
     * @param password
     * @param session
     * @return
     */
    @RequestMapping(value = "login", method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse<User> login(String username, String password, HttpSession session) {
        ServerResponse<User> response = userService.login(username, password);
        if (response.isSuccess()) {
            session.setAttribute(Constant.CURRENT_USER, response.getData());
        }
        return response;
    }

    /**
     * Get user information
     *
     * @param session
     * @return
     */
    @RequestMapping(value = "get_information", method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse<User> get_information(HttpSession session) {
        User user = (User) session.getAttribute(Constant.CURRENT_USER);
        if (user == null) {
            return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "User is not logged on, forced logon is required status=10");
        }
        return userService.getInformation(user.getId());
    }

}

After the user logs in, we save the user information to session through session.setAttribute(). When we get the user information interface, we need to get the current logged in user information in session. If the session does not exist, we will guide the user to log in, otherwise we will do the next operation!

summary

Personally, I feel that the principle of applet custom annotation to get the current logged-in user is not much different from session management current logged-in user mechanism, but it is implemented in a different way. The main step to achieve custom annotation to get the current logged-in user is to customize the logon annotation: @LoginUser Then customize a handler method parameter parser (class) and implement HandlerMethodArgumentResolver, override two methods of the interface, and finally configure our custom parameter parser into the Spring container, so that we can use it in the Controller layer, corresponding to the two methods of HandlerMethodArgumentResolver, which I have explained in my comments.If it's not clear, you can look at his source code to get a better understanding.

Topics: Programming Session Spring Mobile