在Vue+springBoot环境中如何实现单点登录(SSO)

后端:四个接口(注册接口、获取验证码接口、登录接口、获取用户信息接口)

验证码接口(此处短信发送默认成功且验证码为1111,实际上未发送)
    @Autowired
    private MsmService msmService;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    //发送短信方法
    @GetMapping("send/{phone}")
    public R sendMsm(@PathVariable String phone){
        //从redis获取验证码
        String code = redisTemplate.opsForValue().get(phone);

        if (!StringUtils.isEmpty(code)){
            return R.ok();
        }

        //生成随机值,传递到阿里云进行发送
//        code = RandomUtil.getFourBitRandom();发送短信验证码为1111
        code = "1111";
        Map<String,Object> param = new HashMap<>();
        param.put("code",code);
//        boolean isSend = msmService.send(param,phone); 默认发生成功
        boolean isSend = true;
        if (isSend){
            //设置redis中存储数据的时长,电话号/验证码/时间/时间单位
            redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES);
            return R.ok();
        }
        else {
        return R.error().message("短信发送失败");
        }
    }

service层

@Service
public class MsmServiceImpl implements MsmService {
    @Override
    public boolean send(Map<String, Object> param, String phone) {
        //传入map 包含code与随机验证码 手机号
        //如果手机号为空
        if(StringUtils.isEmpty(phone)) return false;
        //传入阿里云的keyid与secret 地区为默认
        DefaultProfile profile =
        DefaultProfile.getProfile("default", "不能告诉你keyid", "不能告诉你secret ");
        IAcsClient client = new DefaultAcsClient(profile);

        //设置相关固定参数
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");

        //设置发送相关参数
        request.putQueryParameter("PhoneNumbers",phone);//手机号
        request.putQueryParameter("SignName","我的Aokil博客");//申请阿里云 签名名称
        request.putQueryParameter("TemplateCode","SMS_210065560");//申请阿里云 模板名称
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));//申请阿里云 验证码

        try {
            CommonResponse response = client.getCommonResponse(request);
            boolean success = response.getHttpResponse().isSuccess();
            return success;
        }catch (Exception e){

        }
        return false;
    }
}

注册接口

    //根据验证码实现注册(验证码接口另调用)
    @PostMapping("register")
    public R registerUser(@RequestBody RegisterVo registerVo){
        memberService.register(registerVo);
        return R.ok();
    }

service

    public void register(RegisterVo registerVo) {

        String code = registerVo.getCode();
        String mobile = registerVo.getMobile();
        String nickname = registerVo.getNickname();
        String password = registerVo.getPassword();
        //判断四项是否为空
        if (StringUtils.isEmpty(code)||
            StringUtils.isEmpty(mobile)||
            StringUtils.isEmpty(nickname)||
            StringUtils.isEmpty(password)){
            throw new GuliException(20001,"注册失败");
        }
        //判断验证码
        String redisCodes= redisTemplate.opsForValue().get(mobile);
        if (!code.equals(redisCodes)){
            throw new GuliException(20001,"注册失败");
        }
        //判断手机号是否重复
        QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
        wrapper.eq("mobile",mobile);
        Integer integer = baseMapper.selectCount(wrapper);
        if(integer>0){
            throw new GuliException(20001,"注册失败");
        }

        UcenterMember member = new UcenterMember();
        member.setMobile(mobile);
        member.setNickname(nickname);
        member.setPassword(MD5.encrypt(password));
        member.setIsDisabled(false);
        member.setAvatar("https://online-teach-file.oss-cn-beijing.aliyuncs.com/teacher/2019/11/08/e44a2e92-2421-4ea3-bb49-46f2ec96ef88.png");
        baseMapper.insert(member);


    }
登录接口
    //根据手机号和密码登录
    @PostMapping("login")
    public R loginUser(@RequestBody UcenterMember member){
        String token = memberService.login(member);
        return R.ok().data("token",token);
    }

service层(加密模式为MD5)

   public String login(UcenterMember member) {
        //获取登录手机号和密码
        String mobile = member.getMobile();
        String password = member.getPassword();
        System.out.println(member);
        //判断用户名密码是否为空
        if (StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)){
            throw new GuliException(20001,"登录失败");
        }
        //判断手机号是否正确
        QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
        wrapper.eq("mobile",mobile);
        UcenterMember ucenterMember = baseMapper.selectOne(wrapper);
        if (ucenterMember == null){
            throw new GuliException(20001,"手机号错误");
        }

        //判断密码
        //先进行加密再判断

        if(!MD5.encrypt(password).equals(ucenterMember.getPassword())){
            throw new GuliException(20001,"密码错误");
        }

        //判断用户是否禁用
        if (ucenterMember.getIsDisabled()){
            throw new GuliException(20001,"用户被禁用");
        }

        //登录成功
        //生成token字符串,使用jwt工具类,返回id与昵称
        String jwtToken = JwtUtils.getJwtToken(ucenterMember.getId(), ucenterMember.getNickname());
        return jwtToken;
    }

MD5工具类

public final class MD5 {

    public static String encrypt(String strSrc) {
        try {
            char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
                    '9', 'a', 'b', 'c', 'd', 'e', 'f' };
            byte[] bytes = strSrc.getBytes();
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(bytes);
            bytes = md.digest();
            int j = bytes.length;
            char[] chars = new char[j * 2];
            int k = 0;
            for (int i = 0; i < bytes.length; i++) {
                byte b = bytes[i];
                chars[k++] = hexChars[b >>> 4 & 0xf];
                chars[k++] = hexChars[b & 0xf];
            }
            return new String(chars);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("MD5加密出错!!+" + e);
        }
    }

    public static void main(String[] args) {
        System.out.println(MD5.encrypt("111111"));
    }

}
根据Token获取用户信息接口(使用JWT获取Token中的信息)
    //根据token获取用户信息
    @GetMapping("getMemberInfo")
    public R getMemberInfo(HttpServletRequest request){
        String memberId= JwtUtils.getMemberIdByJwtToken(request);
        UcenterMember member = memberService.getById(memberId);

        return R.ok().data("userInfo",member);
    }

JWTUtils

public class JwtUtils {

    public static final long EXPIRE = 1000 * 60 * 60 * 24;//token过期时间
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";//秘钥

    //生成token字符串的方法
    public static String getJwtToken(String id, String nickname){

        String JwtToken = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")

                .setSubject("aokill-user")

                //设置过期时间
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))

                //设置token的主体部分,用来存储用户信息
                .claim("id", id)
                .claim("nickname", nickname)

                //签名hash
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }

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

    /**
     * 判断token是否存在与有效
     * @param request
     * @return
     */
    public static boolean checkToken(HttpServletRequest request) {
        try {
            String jwtToken = request.getHeader("token");
            if(StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取会员id
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("id");
    }
}

四个接口写好了,现在开始前端的流程

前端 根据Token获取用户信息

  • 1.调用登录接口 登录成功返回Token字符串
  • 2.把第一步返回的Token字符串放入Cookie里
  • 3.创建前端拦截器,判断Cookie里面是否有Token字符串,如果有,把Token字符串放入header请求头中
  • 4.根据Token值,调用接口,根据token获取用户信息,把返回的信息放到cookie中
  • 5.在页面显示用户信息,从第四步cookie获取用户信息
登录的方法

API

    //登录的方法
  submitLoginUser(member) {
    return request({
      url: `/educenter/member/login`,
      method: 'post',
      data:member
    })
  },
   //获取Token中信息的方法
  getLoginUserInfo() {
    return request({
      url: `/educenter/member/getMemberInfo`,
      method: 'get'
    })
  },

页面中

    methods: {

      //登录的方法
      submitLogin(){
        //第一步进行接口调用,返回token字符串
        login.submitLoginUser(this.user)
        .then(response =>{
          //第二步 获取token字符串放到cookie中
          //第一个参数是cookie名称,第二个参数值,第三个参数作用范围
          cookie.set('guli_token',response.data.data.token,{domain:'localhost'})
          
          //第四部 调用接口 根据token获取用户信息,为了首页面显示
          loign.getLoginUserInfo()
          .then(response => {
            this.loginInfo = response.data.data.userInfo
            //获取返回用户信息,放到cookie中
            cookie.set('aokill_ucenter',this.loginInfo,{domain:'localhost'})
          })
          window.location.href = "/";
        })
      }
      
    }

第三步的拦截器要放在request.js中,因为每个api都会导入request.js

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import cookie from 'js-cookie'
// 创建axios实例
const service = axios.create({
  baseURL: 'http://localhost:9001', // api的base_url
  timeout: 20000 // 请求超时时间
})

//拦截器 如果有cookie值 则放到请求头中
service.interceptors.request.use(

  config => {
    if(cookie.get('aokill_token')){
      config.headers['token'] = cookie.get('aokill_token');
    }
    return config
  },
  err => {
    return Promise.reject(err);
  })

  //------
export default service

那么如何在页面中获取数据呢?记得导入js-cookie

 import cookie from 'js-cookie' 
 created(){
    this.showInfo()
  },
  methods:{
      //创建方法,从cookie获取用户信息
      showInfo(){
        //从cookie获取用户信息
        var userStr = cookie.get('aokill_ucenter')
        //把字符串转换成json对象
        if(userStr){
          this.loginInfo = JSON.parse(userStr)
        }
      }
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值