美文网首页
七、微服务之用户服务

七、微服务之用户服务

作者: 薛定谔的猫_1406 | 来源:发表于2018-06-19 21:56 被阅读0次

一、用户服务基于JWT的token认证实现

传统的session身份认证
  • 缺点:session存储在内存中,这样就不能跨实例共享,当下一次请求分发到另外的实例中,就要重新登陆;
  • session是依赖于浏览器的cookie,当移动端访问的时候就很难支持。


    基于token的认证
  • 优点:1保证了服务的无状态,因为用户信息都是存在分布式缓存中;
  • 2 .不依赖于token机制,可以根据与客户端约定的协议来传输token。


    基于JWT的身份认证(JSON WEB TOKENS)
    JWT身份认证

二、实现

2.1 引入jwt的依赖

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java.jwt</artifactId>
</denpendency>

2.2 定义JwtHelper,来生成token

package com.mooc.house.user.utils;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.time.DateUtils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.collect.Maps;

public class JwtHelper {
  
  private static final String  SECRET = "session_secret";
  
  private static final String  ISSUER = "mooc_user";
  
  /**
  * 生成token的方法
  *@Param claims 表示将用户的哪些数据设置到token里,比如用户的姓名或者email。这样减少了数据库的压力,从token里获取用户信息
*/
  public static String genToken(Map<String, String> claims){
    try {
      //定义算法
      Algorithm algorithm = Algorithm.HMAC256(SECRET);
      //设置发布者 、过期时间信息
      JWTCreator.Builder builder = JWT.create().withIssuer(ISSUER).withExpiresAt(DateUtils.addDays(new Date(), 1));
    //将用户信息设置到token中
      claims.forEach((k,v) -> builder.withClaim(k, v));
      return builder.sign(algorithm).toString();
    } catch (IllegalArgumentException | UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }
  
  /**
  * 校验操作
*/
  public static Map<String, String> verifyToken(String token)  {
    Algorithm algorithm = null;
    try {
      algorithm = Algorithm.HMAC256(SECRET);
    } catch (IllegalArgumentException | UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
    JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
    DecodedJWT jwt =  verifier.verify(token);
    Map<String, Claim> map = jwt.getClaims();
    Map<String, String> resultMap = Maps.newHashMap();
    map.forEach((k,v) -> resultMap.put(k, v.asString()));
    return resultMap;
  }

}

2.3 service层操作

vpackage com.mooc.house.user.service;

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.mooc.house.user.common.UserException;
import com.mooc.house.user.common.UserException.Type;
import com.mooc.house.user.mapper.UserMapper;
import com.mooc.house.user.model.User;
import com.mooc.house.user.utils.BeanHelper;
import com.mooc.house.user.utils.HashUtils;
import com.mooc.house.user.utils.JwtHelper;

@Service
public class UserService {

  @Autowired
  private StringRedisTemplate redisTemplate;
  
  @Autowired
  private UserMapper userMapper;
  
  @Autowired
  private MailService mailService;
  

  @Value("${file.prefix}")
  private String imgPrefix;
  
  /**
   * 1.首先通过缓存获取
   * 2.不存在将从通过数据库获取用户对象
   * 3.将用户对象写入缓存,设置缓存时间5分钟
   * 4.返回对象
   * @param id
   * @return
   */
  public User getUserById(Long id) {
    String key = "user:"+id;
    String json =  redisTemplate.opsForValue().get(key);
    User user = null;
    if (Strings.isNullOrEmpty(json)) {
      user =  userMapper.selectById(id);
      user.setAvatar(imgPrefix + user.getAvatar());
      String string  = JSON.toJSONString(user);
      redisTemplate.opsForValue().set(key, string);
      redisTemplate.expire(key, 5, TimeUnit.MINUTES);
    }else {
      user = JSON.parseObject(json,User.class);
    }
    return user;
  }

  public List<User> getUserByQuery(User user) {
    List<User> users = userMapper.select(user);
    users.forEach(u -> {
      u.setAvatar(imgPrefix + u.getAvatar());
    });
    return users;
  }

  /**
   * 注册
   * @param user
   * @param enableUrl
   * @return
   */
  public boolean addAccount(User user, String enableUrl) {
    user.setPasswd(HashUtils.encryPassword(user.getPasswd()));
    BeanHelper.onInsert(user);
    userMapper.insert(user);
    registerNotify(user.getEmail(),enableUrl);
    return true;
  }

  /**
   * 发送注册激活邮件
   * @param email
   * @param enableUrl
   */
  private void registerNotify(String email, String enableUrl) {
    String randomKey = HashUtils.hashString(email) + RandomStringUtils.randomAlphabetic(10);
    redisTemplate.opsForValue().set(randomKey, email);
    redisTemplate.expire(randomKey, 1,TimeUnit.HOURS);
    String content = enableUrl +"?key="+  randomKey;
    mailService.sendSimpleMail("房产平台激活邮件", content, email);
  }

  public boolean enable(String key) {
    String email = redisTemplate.opsForValue().get(key);
    if (StringUtils.isBlank(email)) {
       throw new UserException(UserException.Type.USER_NOT_FOUND, "无效的key");
    }
    User updateUser = new User();
    updateUser.setEmail(email);
    updateUser.setEnable(1);
    userMapper.update(updateUser);
    return true;
  }

  /**
   * 校验用户名密码、生成token并返回用户对象
   * @param email
   * @param passwd
   * @return
   */
  public User auth(String email, String passwd) {
    if (StringUtils.isBlank(email) || StringUtils.isBlank(passwd)) {
      throw new UserException(Type.USER_AUTH_FAIL,"User Auth Fail");
    }
    User user = new User();
    user.setEmail(email);
    user.setPasswd(HashUtils.encryPassword(passwd));
    user.setEnable(1);
    List<User> list =  getUserByQuery(user);
    if (!list.isEmpty()) {
       User retUser = list.get(0);
       onLogin(retUser);
       return retUser;
    }
    throw new UserException(Type.USER_AUTH_FAIL,"User Auth Fail");
  }

  private void onLogin(User user) {
    String token =  JwtHelper.genToken(ImmutableMap.of("email", user.getEmail(), "name", user.getName(),"ts",Instant.now().getEpochSecond()+""));
    renewToken(token,user.getEmail());
    user.setToken(token);
  }

  private String renewToken(String token, String email) {
    redisTemplate.opsForValue().set(email, token);
    redisTemplate.expire(email, 30, TimeUnit.MINUTES);
    return token; 
  }

  public User getLoginedUserByToken(String token) {
    Map<String, String> map = null;
    try {
      map = JwtHelper.verifyToken(token);
    } catch (Exception e) {
      throw new UserException(Type.USER_NOT_LOGIN,"User not login");
    }
    String email =  map.get("email");
    Long expired = redisTemplate.getExpire(email);
    if (expired > 0L) {
      renewToken(token, email);
      User user = getUserByEmail(email);
      user.setToken(token);
      return user;
    }
    throw new UserException(Type.USER_NOT_LOGIN,"user not login");
    
  }

  private User getUserByEmail(String email) {
    User user = new User();
    user.setEmail(email);
    List<User> list = getUserByQuery(user);
    if (!list.isEmpty()) {
      return list.get(0);
    }
    throw new UserException(Type.USER_NOT_FOUND,"User not found for " + email);
  }

  public void invalidate(String token) {
    Map<String, String> map = JwtHelper.verifyToken(token);
    redisTemplate.delete(map.get("email"));
  }

  @Transactional(rollbackFor = Exception.class)
  public User updateUser(User user) {
     if (user.getEmail() == null) {
        return null;
     }
     if (!Strings.isNullOrEmpty(user.getPasswd()) ) {
        user.setPasswd(HashUtils.encryPassword(user.getPasswd()));
     }
     userMapper.update(user);
     return userMapper.selectByEmail(user.getEmail());
  }

  public void resetNotify(String email,String url) {
    String randomKey = "reset_" + RandomStringUtils.randomAlphabetic(10);
    redisTemplate.opsForValue().set(randomKey, email);
    redisTemplate.expire(randomKey, 1,TimeUnit.HOURS);
    String content = url +"?key="+  randomKey;
    mailService.sendSimpleMail("房产平台重置密码邮件", content, email);
    
  }

  public String getResetKeyEmail(String key) {
    return  redisTemplate.opsForValue().get(key);
  }

  public User reset(String key, String password) {
    String email = getResetKeyEmail(key);
    User updateUser = new User();
    updateUser.setEmail(email);
    updateUser.setPasswd(HashUtils.encryPassword(password));
    userMapper.update(updateUser);
    return getUserByEmail(email);
  }

}
登陆验证
鉴权
登出

2.4 jwt的优势

jwt的优势

2.5 jwt的缺点

jwt的缺点

相关文章

  • 你问我答之《微博用户服务使用协议》引发了什么版权争议?

    你问我答之 《微博用户服务使用协议》引发了什么版权争议? 不久前,新浪微博修改用户协议,主要包括:用户发布在新浪微...

  • 丰巢到底怎么了

    5月15日,也就是今晚8:40,丰巢科技推出一条微信《关于用户服务调整的说明》。 对用户服务调整了三点: 其一、只...

  • 用户服务

    layout: docs-default 用户服务 用户服务的例子,请看这里 IdentityServer3 定义...

  • 七、微服务之用户服务

    一、用户服务基于JWT的token认证实现 缺点:session存储在内存中,这样就不能跨实例共享,当下一次请求分...

  • 20190822《任正非讲稿》阅读总结

    22/31《加强用户服务中心建设,不断提高用户服务水平》——任正非在用户服务中心97 年管理培训班上的讲话1997...

  • 搭建MAVEN项目

    创建基于MAVEN的顶级工程 创建服务-用户服务模块 创建服务公布-用户服务出口 初阶段项目结构 在顶级父项目中引...

  • 《官途无限》用户协议

    《用户服务协议》 本《用户服务协议》(以下简称《协议》)是由您(以下简称“用户”)就本游戏服务与我方签订的协议。 ...

  • 《当朝宰相》用户协议

    《用户服务协议》 本《用户服务协议》(以下简称《协议》)是由您(以下简称“用户”)就本游戏服务与我方签订的协议。 ...

  • 《参见官老爷》用户协议

    《用户服务协议》 本《用户服务协议》(以下简称《协议》)是由您(以下简称“用户”)就本游戏服务与我方签订的协议。 ...

  • 用户协议

    《用户服务协议》 本《用户服务协议》(以下简称《协议》)是由您(以下简称“用户”)就本游戏服务与我方签订的协议。 ...

网友评论

      本文标题:七、微服务之用户服务

      本文链接:https://www.haomeiwen.com/subject/tjszeftx.html