基於使用者認證的前後端實現

chengqiuming發表於2020-12-27

一 準備

1 引入依賴

common-util中引入jwt依賴

<!-- JWT相關依賴-->
<dependencies>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
    </dependency>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>
</dependencies>

2 引入工具類

common-util中引入工具類:JwtUtils.java、JwtInfo.java

JwtUtils.java

public class JwtUtils {
    /**
     * 金鑰字串
     */
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

    /**
     * 功能描述:獲得金鑰例項
     *
     * @return Key 金鑰例項
     * @author cakin
     * @date 2020/12/27
     */
    private static Key getKeyInstance() {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        byte[] bytes = DatatypeConverter.parseBase64Binary(APP_SECRET);
        return new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
    }

    /**
     * 功能描述:獲取Jwt的token
     *
     * @param jwtInfo 使用者資訊
     * @param expire 過期時間
     * @return String
     * @author cakin
     * @date 2020/12/27
     */
    public static String getJwtToken(JwtInfo jwtInfo, int expire) {
        String JwtToken = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setSubject("guli-user") // 主題
                .setIssuedAt(new Date()) // 頒發時間
                .setExpiration(DateTime.now().plusSeconds(expire).toDate()) // 過期時間
                .claim("id", jwtInfo.getId()) // 使用者id
                .claim("nickname", jwtInfo.getNickname()) // 使用者暱稱
                .claim("avatar", jwtInfo.getAvatar()) // 使用者頭像
                .signWith(SignatureAlgorithm.HS256, getKeyInstance())
                .compact();
        return JwtToken;
    }

    /**
     * 判斷token是否存在與有效
     *
     * @param jwtToken jwtToken
     * @return boolean 是否有效
     */
    public static boolean checkJwtTToken(String jwtToken) {
        if (StringUtils.isEmpty(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判斷token是否存在與有效
     *
     * @param request http請求
     * @return boolean JWT是否有效
     */
    public static boolean checkJwtTToken(HttpServletRequest request) {
        try {
            String jwtToken = request.getHeader("token");
            if (StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    /**
     * 根據token獲取會員id
     *
     * @param request http請求
     * @return JwtInfo JWt中的會員資訊
     */
    public static JwtInfo getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        if (StringUtils.isEmpty(jwtToken)) return null;
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        JwtInfo jwtInfo = new JwtInfo(claims.get("id").toString(), claims.get("nickname").toString(), claims.get("avatar").toString());
        return jwtInfo;
    }
}

JwtInfo.java

@Data
@AllArgsConstructor
@NoArgsConstructor
public class JwtInfo {
    /**
     * 使用者id
     */
    private String id;
    /**
     * 暱稱
     */
    private String nickname;
    /**
     * 影像
     */
    private String avatar;
    //許可權、角色等
    //不要存敏感資訊
}

二 使用者登入介面

1 定義LoginVo

/**
* @className: LoginVo
* @description: 使用者登入資訊
* @date: 2020/12/27
* @author: cakin
*/
@Data
public class LoginVo implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 手機號
     */
    private String mobile;
    /**
     * 使用者密碼
     */
    private String password;
}

2 service實現登入

介面:MemberService

/**
* 功能描述:登入介面
*
* @author cakin
* @date 2020/12/27
* @param loginVo 使用者登入資訊
* @return String Jwt token
*/
String login(LoginVo loginVo);

實現: MemberServiceImpl

/**
* 功能描述:登入介面
*
* @param loginVo 使用者登入資訊
* @return String Jwt token
* @author cakin
* @date 2020/12/27
*/
@Override
public String login(LoginVo loginVo) {
    String mobile = loginVo.getMobile();
    String password = loginVo.getPassword();
    // 校驗:引數(手機號、密碼)是否合法
    if (StringUtils.isEmpty(mobile)
            || !FormUtils.isMobile(mobile)
            || StringUtils.isEmpty(password)) {
        throw new GuliException(ResultCodeEnum.PARAM_ERROR);
    }
    // 校驗手機號是否存在
    QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("mobile", mobile);
    Member member = baseMapper.selectOne(queryWrapper);
    if (member == null) {
        throw new GuliException(ResultCodeEnum.LOGIN_MOBILE_ERROR);
    }
    // 校驗密碼是否正確
    if (!MD5.encrypt(password).equals(member.getPassword())) {
        throw new GuliException(ResultCodeEnum.LOGIN_PASSWORD_ERROR);
    }
    // 校驗使用者是否被禁用
    if (member.getDisabled()) {
        throw new GuliException(ResultCodeEnum.LOGIN_DISABLED_ERROR);
    }
    // 登入:生成token
    JwtInfo info = new JwtInfo();
    info.setId(member.getId());
    info.setNickname(member.getNickname());
    info.setAvatar(member.getAvatar());
    String jwtToken = JwtUtils.getJwtToken(info, 1800);
    return jwtToken;
}

3 登入介面

/**
* 功能描述:登入介面
*
* @author cakin
* @date 2020/12/27
* @param loginVo 登入資訊
* @return R 返回給前端的資訊
*/
@ApiOperation(value = "會員登入")
@PostMapping("login")
public R login(@RequestBody LoginVo loginVo){
    String token = memberService.login(loginVo);
    return R.ok().data("token", token).message("登入成功");
}

三 前端整合

1 安裝cookie模組

npm install js-cookie@2.2.0

2 api

import request from '~/utils/request'
// import cookie from 'js-cookie'
// 提交登入資訊
export default {
  submitLogin(user) {
    return request({
      baseURL: 'http://localhost:8160',
      url: '/api/ucenter/member/login',
      method: 'post',
      data: user
    })
  },
}

3 登入頁核心程式碼

import cookie from 'js-cookie'
import loginApi from '~/api/login'
export default {
  layout: 'sign',
  data() {
    return {
      user: {
        mobile: '',
        password: ''
      }
    }
  },
  methods: {
    // 登入
    submitLogin() {
      // 執行遠端登入介面呼叫
      loginApi.submitLogin(this.user).then(response => {
        // 將jwt寫入cookie
        cookie.set('guli_jwt_token', response.data.token, { domain: 'localhost' })
        // 跳轉到網站的首頁面
        window.location.href = '/'
      })
    }
  }
}
</script>

4 測試

檢視cookie中儲存了jwtToken值

相關文章