springboot项目实战---使用redis进行鉴权

不使用shrio安全框架,直接使用token+redis进行鉴权


个人商城的项目,考虑只需要做用户认证,就没用引入shrio等框架。直接往redis存token,然后进行校验,以此进行登录认证

实体类TokenModel

@Data
public class TokenModel {
    private String userId;

    private String token;

    public TokenModel(String userId,String token){
        this.userId = userId;
        this.token = token;
    }
    }

创建注解,在controller层中使用

@autorization 是否需要登录

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autorization {
}

注解实现:

@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private TokenManager manager;

    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        //如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            response.sendError(401,"请登录");
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        //从header中得到token
        String authorization = request.getHeader(Constants.AUTHORIZATION);
        //验证token
        TokenModel model = manager.getToken(authorization);
        if (manager.checkToken(model)) {
            //如果token验证成功,将token对应的用户id存在request中,便于之后注入
            request.setAttribute(Constants.CURRENT_USER_ID, model.getUserId());
            return true;
        }
        //如果验证token失败,并且方法注明了Authorization,返回401错误
        if (method.getAnnotation(Autorization.class) != null) {
            response.sendError(401,"请登录");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        return true;
    }
}

@Currentuser 校验用户

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autorization {
}

注解实现:

@Component
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Autowired
    private UserServer userServer;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //如果参数类型是User并且有CurrentUser注解则支持
        if (parameter.getParameterType().isAssignableFrom(User.class) &&
                parameter.hasParameterAnnotation(CurrentUser.class)) {
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        //取出鉴权时存入的登录用户Id
        String currentUserId = (String) webRequest.getAttribute(Constants.CURRENT_USER_ID, RequestAttributes.SCOPE_REQUEST);
        if (currentUserId != null) {
            //从数据库中查询并返回
            return userServer.getUserById(currentUserId);
        }
        throw new MissingServletRequestPartException(Constants.CURRENT_USER_ID);
    }
}

service层,创建token,校验token

@Component
public class TokenManagerImpl implements TokenManager {


    @Resource
    private RedisTemplate<String, String> redis;


    public void setRedis(RedisTemplate redis) {
        this.redis = redis;
        //泛型设置成Long后必须更改对应的序列化方案
        redis.setKeySerializer(new JdkSerializationRedisSerializer());
    }


    public TokenModel createToken(String userId) {
        //使用uuid作为源token
        String token = UUID.randomUUID().toString().replace("-", "");
        TokenModel model = new TokenModel(userId, token);
        //存储到redis并设置过期时间
        redis.boundValueOps(userId).set(token, Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
        return model;
    }

    public boolean checkToken(TokenModel model) {
        if (model == null) {
            return false;
        }
        String token = redis.boundValueOps(model.getUserId()).get();
        if (token == null || !token.equals(model.getToken())) {
            return false;
        }
        //如果验证成功,说明此用户进行了一次有效操作,延长token的过期时间
        redis.boundValueOps(model.getUserId()).expire(Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
        return true;
    }

    public TokenModel getToken(String authentication) {
        if (authentication == null || authentication.length() == 0) {
            return null;
        }
        String[] param = authentication.split("_");
        if (param.length != 2) {
            return null;
        }
        //使用userId和源token简单拼接成的token,可以增加加密措施
        String userId = param[0];
        String token = param[1];
        return new TokenModel(userId, token);
    }

    public void deleteToken(String userId) {
        redis.delete(userId);
    }

}

controller层进行登录

    @PostMapping("/login")
    public Object Login(@RequestBody Map<String, Object> reqMap) {
        String userName = RequestUtil.getMapString(reqMap.get("user_name").toString());
        String passWord = RequestUtil.getMapString(reqMap.get("pass_word").toString());
        //判断用户名是否存在
        User user = userServer.getUser(userName);
        if (user == null) {
            return ResultUtil.fail(ResultEnum.LOGIN_FAIL);
        }
        //获取数据库中的密码,与输入的密码加密后比对
        String dbPassword = user.getPassWord();
        String equalPassword = MD5Util.inputPassToDbPass(passWord);
        if (!equalPassword.equals(dbPassword)) {
            return ResultUtil.fail(ResultEnum.LOGIN_FAIL_PASS);
        }
        //生成一个token,保存用户登录状态
        TokenModel model = tokenManager.createToken(user.getId());
        return ResultUtil.ok(model);
    }

商城项目地址
https://github.com/627886474/sneaker
欢迎start,如有不足,还请指教。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值