如何通过自定义注解获取用户登录信息

前言

最近在做权限管理,需要获取用户所属的角色信息,但是这些信息通过前端传参很不安全。大家可以试想这么一个场景:有两个用户A和B,A的角色是1,B的角色是2;我登录的是A用户,如果通过前端手动传入角色id获取信息(/getValue/1),我就可以绕过前端,手动向后端发送:/getValue/2,获取不属于我角色能获取到的信息,这样就会出现安全问题。那么这样的问题有解吗?肯定是有的!如果你还是偏爱前端传递,那么只需要把前端传递的roleId和登录角色的roleId进行比较,但是这样操作起来就很麻烦。

获取用户登录信息

如果我们不用前端传递参数呢?那就可以从请求头中获取用户的登录信息!每一个登录后的请求都会携带token或cookie

因此我们就可以通过请求头获取用户的登录信息

public R responsibleNameList(HttpServletRequest request) {
        String authorization = request.getHeader("Authorization");
        String userByToken = userTokenService.getUserByToken(authorization);
        User user = userService.getById(Long.valueOf(userByToken));
       ......
    }

其中,getUserByToken方法要看你们的项目在用户登录拦截时,如何保存的用户信息,以我的项目为例,我们保存在了redis中

......
// 登录成功发放token令牌
        String token = userTokenService.createToken(userInfo.getName(), String.valueOf(userInfo.getId()));
......
@Service
public class UserTokenServiceImpl implements UserTokenService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private TokenProvider tokenProvider;


    @Override
    public void refreshToken(String token) {
        redisTemplate.expire(token, securityProperties.getRenew(), TimeUnit.MILLISECONDS);
    }


    @Override
    public String getToken(String userId) {
        return (String) redisTemplate.opsForValue().get(securityProperties.getUserLoginKey() + userId);
    }


    @Override
    public String createToken(String username, String userId) {
        String token = tokenProvider.createToken(username);

        //token保存到redis
        this.saveUser(token, userId, securityProperties.getTokenValidityInSeconds());
        return token;
    }


    @Override
    public void saveUser(String token, String userId, Long time) {
        if (!securityProperties.isMultiLogin()) {
            Object oldTokenKey = redisTemplate.opsForValue().get(securityProperties.getUserLoginKey() + userId);
            if (oldTokenKey != null) {
                redisTemplate.delete(oldTokenKey);
            }
        }
        redisTemplate.opsForValue().set(token, userId, time, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(securityProperties.getUserLoginKey() + userId, token);
    }


    @Override
    public String getUserByToken(String token) {
        return (String) redisTemplate.opsForValue().get(token);
    }
}

通过该方式,就可以获取到用户的登录信息。

但是这样的话,我每个需要用户登录信息的请求,都要执行一遍request.getHeander吗?答案是yes,是的,不用我说,你也会觉得这样的方式很麻烦,对吧?

获取用户信息进阶版

在我们学习Spring时,我们知道,所有的请求都会经过拦截器的拦截处理,然后放行;我们又知道,注解可以简化一些通用的操作,比如@Data就简化了对象的get和set方法。那么我们是不是可以将以上两者结合起来,简化我们的开发?答案一定是yes!

首先,我们定义了一个自定义注解

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {
}

然后编写一个登录处理器

@Component
public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Resource
    private UserService userService;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(CurrentUser.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container,
                                  NativeWebRequest request, WebDataBinderFactory factory) {
       
        String authorization = request.getHeader("Authorization");
        String userByToken = userTokenService.getUserByToken(authorization);
        User user = userService.getById(Long.valueOf(userByToken));
        return user;
    }
}

最后在Spring中配置该处理器

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private LoginUserHandlerMethodArgumentResolver loginUserHandlerMethodArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(loginUserHandlerMethodArgumentResolver);
    }
......
}

这样就完成了!只需要在请求中加入我们的注解

public R responsibleNameList(@CurrentUser User user) {
       // 直接进行后续的操作
       ......
    }

总结

使用自定义注解可以极大的简化我们的代码开发,但是也要结合实际的业务需求,不能为了注解而注解。谢谢大家的观看,我们下次再见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YuuuZh。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值