首页 > 其他分享 >第三方登录组件-JustAuth

第三方登录组件-JustAuth

时间:2022-12-09 13:33:56浏览次数:48  
标签:登录 request springframework source sysUser org 组件 import JustAuth

1、新增依赖

<dependency>
   <groupId>me.zhyd.oauth</groupId>
   <artifactId>JustAuth</artifactId>
   <version>1.16.5</version>
</dependency>

2、前端示例

<template>
  <div class="social-signup-container">
    <div class="sign-btn" @click="thirdLoginClick('wechat')">
      <span class="wx-svg-container"><svg-icon icon-class="wechat" class="icon"/></span>
      微信
    </div>
    <div class="sign-btn" @click="thirdLoginClick('qq')">
      <span class="qq-svg-container"><svg-icon icon-class="qq" class="icon"/></span>
      QQ
    </div>
    <div class="sign-btn" @click="thirdLoginClick('gitee')">
      <span class="gitee-svg-container"><svg-icon icon-class="gitee" class="icon"/></span>
      Gitee
    </div>
  </div>
</template>
<script>
export default {
name: 'SocialSignin',
methods: {
   // 请求后台获取跳转路径
thirdLoginClick(source) {
this.$store.dispatch('user/thirdLogin', {source: source}).then(() => {
}).catch(() => {
})
}
}
}
</script>
  // 第三方登录
  thirdLogin({commit}, userInfo) {
    const {source} = userInfo
    return new Promise((resolve, reject) => {
      thirdLogin({source: source.trim()}).then(response => {
        console.log("第三方登录返回", response)
        if (response.data.code === "200") {
          window.location.href = response.data.url
        } else {
          Message.warning(response.data.msg);
        }
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  }
export function thirdLogin(data) {
  return request({
    url: '/login/render',
    method: 'post',
    params: {source: data.source}
  })
}

3、后端示例

获取跳转路径
import com.mxy.common.core.utils.ServiceResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;

/**
 * 第三方登录认证
 */
@RestController
@RequestMapping("/api/login")
@Api(value = "第三方登录相关接口", tags = {"第三方登录相关接口"})
@Slf4j
public class AuthRestApi {

    @Resource
    private AuthUtil authUtil;

    @ApiOperation(value = "系统认证", notes = "系统认证")
    @RequestMapping("/render")
    public String renderAuth(String source) {
        log.info("进入第三方认证:" + source);
        Map<String, String> map = new HashMap<>();
        AuthRequest authRequest = authUtil.getAuthRequest(source);
        if (authRequest == null) {
            map.put("code", "201");
            map.put("msg", "系统未开启该登录方式");
            return ServiceResult.success(map);
        }
        String token = AuthStateUtils.createState();
        String authorizeUrl = authRequest.authorize(token);
        log.info("获取返回url:" + authorizeUrl);
        map.put("code", "200");
        map.put("url", authorizeUrl);
        return ServiceResult.success(map);
    }

}

拦截登录回调接口(ThirdPartyAuthenticationFilter)

import me.zhyd.oauth.model.AuthCallback;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 第三方登录-拦截器
 * 拼接入参
 */
public class ThirdPartyAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public static String EXTEND_LOGIN_URL = "/api/login/callback/**";

    private boolean getOnly = true;

    /**
     * 表示这个 Filter 拦截 /api/login/callback/** 接口
     */
    private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(EXTEND_LOGIN_URL, "GET");

    public ThirdPartyAuthenticationFilter() {
        super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (this.getOnly && !"GET".equals(request.getMethod())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        } else {
            ThirdPartyAuthenticationToken authRequest = new ThirdPartyAuthenticationToken(getSourceType(request), getCallback(request));
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }

    protected void setDetails(HttpServletRequest request, ThirdPartyAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    /**
     * 组装请求
     */
    private AuthCallback getCallback(HttpServletRequest request) {
        return AuthCallback.builder()
                .code(request.getParameter("code"))
                .auth_code(request.getParameter("auth_code"))
                .authorization_code(request.getParameter("authorization_code"))
                .oauth_token(request.getParameter("oauth_token"))
                .state(request.getParameter("state"))
                .oauth_verifier(request.getParameter("oauth_verifier"))
                .build();
    }

    /**
     * 判断-登录系统类型
     */
    private String getSourceType(HttpServletRequest request) {
        String uri = request.getRequestURI();
        int common = EXTEND_LOGIN_URL.length() - 2;
        int start = uri.indexOf(EXTEND_LOGIN_URL.substring(0, common));
        return uri.substring(start + common);
    }

}
封装用户信息(ThirdPartyAuthenticationToken)
import me.zhyd.oauth.model.AuthCallback;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;

/**
 * 模仿 UsernamePasswordAuthenticationToken
 * 封装用户信息
 */
public class ThirdPartyAuthenticationToken extends AbstractAuthenticationToken {

    /**
     * 认证返回
     */
    private AuthCallback callback;
    /**
     * 登录类型
     */
    private String source;
    /**
     * 用户实体
     */
    private Object principal;
    /**
     * 用户id
     */
    private Object credentials;

    public ThirdPartyAuthenticationToken(String source, AuthCallback callback) {
        super(null);
        this.source = source;
        this.callback = callback;
        setAuthenticated(false);
    }

    public ThirdPartyAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }

    @Override
    public Object getPrincipal() {
        return principal;
    }

    @Override
    public Object getCredentials() {
        return credentials;
    }

    public Object getCallback() {
        return callback;
    }

    public Object getSource() {
        return source;
    }
}
第三方统一登录认证逻辑(ThirdPartyAuthenticationProvider)
package com.mxy.security.justauth;

import com.alibaba.fastjson.JSONObject;
import com.mxy.common.core.constant.Constants;
import com.mxy.common.core.entity.SelfUserEntity;
import com.mxy.common.core.entity.SysRole;
import com.mxy.common.core.entity.SysUser;
import com.mxy.common.core.entity.SysUserRole;
import com.mxy.common.core.utils.IPUtils;
import com.mxy.common.core.utils.RedisUtil;
import com.mxy.common.core.utils.ServletUtils;
import com.mxy.common.log.enums.OperType;
import com.mxy.security.security.service.SelfUserDetailsService;
import com.mxy.system.service.SysUserService;
import com.mxy.system.utils.LogUtil;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

/**
 * 第三方统一登录认证逻辑
 */
@Slf4j
@Component
public class ThirdPartyAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private SelfUserDetailsService selfUserDetailsService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private AuthUtil authUtil;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    private Random random = new Random();


    /**
     * 第三方统一登录认证逻辑
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        ThirdPartyAuthenticationToken token = (ThirdPartyAuthenticationToken) authentication;
        String source = (String) token.getSource();
        AuthCallback callback = (AuthCallback) token.getCallback();
        log.info("------------进入" + source + "认证逻辑, callback params:" + JSONObject.toJSONString(callback));
        AuthRequest authRequest = authUtil.getAuthRequest(source);
        AuthResponse response = authRequest.login(callback);
        if (response.getCode() == 5000) {
            // 认证失败
            throw new BadCredentialsException(source + "认证失败");
        }
        AuthUser authUser = (AuthUser) response.getData();
        log.info("------------认证用户:{}", authUser);
        // 根据 uuid 查询用户信息
        SelfUserEntity userInfo = selfUserDetailsService.getUserInfoByUuid(authUser.getUuid());
        if (userInfo == null) {
            // 自动注册
            userInfo = doRegister(authUser);
        }
        if (Constants.USER_STATE_TWO.equals(userInfo.getStatus())) {
            LogUtil.saveLog("该账号已冻结[" + userInfo.getRelName() + "]", 99);
            throw new LockedException("该账号已冻结");
        }
        // 角色集合
        Set<GrantedAuthority> authorities = new HashSet<>();
        // 查询用户角色
        List<SysRole> sysRoleList = sysUserService.selectSysRoleByUserId(userInfo.getUserId());
        for (SysRole sysRole : sysRoleList) {
            authorities.add(new SimpleGrantedAuthority(sysRole.getRoleKey()));
        }
        userInfo.setAuthorities(authorities);
        ThirdPartyAuthenticationToken authenticationResult = new ThirdPartyAuthenticationToken(userInfo, userInfo.getUserId(), userInfo.getAuthorities());
        authenticationResult.setDetails(token.getDetails());
        return authenticationResult;
    }

    /**
     * 账号注册
     **/
    public SelfUserEntity doRegister(AuthUser authUser) {
        SelfUserEntity selfUser = new SelfUserEntity();
        SysUser sysUser = new SysUser();
        sysUser.setNickName(authUser.getNickname());
        sysUser.setUsername(authUser.getSource() + (random.nextInt(89999999) + 10000000));
        String password = String.valueOf(random.nextInt(899999) + 100000);
        sysUser.setPassword(bCryptPasswordEncoder.encode(password));
        sysUser.setAvatar(authUser.getAvatar());
        sysUser.setRegistrationType(authUser.getSource());
        sysUser.setUuid(authUser.getUuid());
        sysUser.setLoginCount(0);
        sysUser.setIpSource(IPUtils.getClientIp(Objects.requireNonNull(ServletUtils.getRequest())));
        // 2-男
        sysUser.setSex("2".equals(authUser.getRawUserInfo().getString("gender_type")) ? "0" : "1");
        sysUser.setCreateUser("system");
        sysUser.setRemark(authUser.getSource() + "首次注册默认密码为:" + password);
        sysUser.setLoginDate(new Date());
        sysUser.setUserType("2");
        sysUser.insert();

        // 新增用户角色关系
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(sysUser.getUserId());
        // 游客
        sysUserRole.setRoleId("2");
        sysUserRole.insert();
        BeanUtils.copyProperties(sysUser, selfUser);
        selfUser.setRelName(sysUser.getNickName());
        LogUtil.saveNoLoginLog("账号注册(" + authUser.getSource() + ")", JSONObject.toJSONString(sysUser), OperType.REGISTRATION.ordinal());
        return selfUser;
    }


    /**
     * 判断是上面 authenticate 方法的 authentication 参数,是哪种类型
     * Authentication 是个接口,实现类有很多,目前我们最熟悉的就是 ThirdPartyAuthenticationToken、UsernamePasswordAuthenticationToken
     * 很明显,我们只支持 ThirdPartyAuthenticationToken,因为它封装的是TOKEN OPENID
     *
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return (ThirdPartyAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

 

标签:登录,request,springframework,source,sysUser,org,组件,import,JustAuth
From: https://www.cnblogs.com/xu-m/p/16968685.html

相关文章

  • 【Spring】装配Bean 组件扫描
    实现自动装配需要用注解:注解分为spring规范和java规范,java规范需要引入javax.inject包,使用maven,直接引入。从中可以看到@Named@Inject属于java规范,@Component @Auto......
  • ubuntu20.04下安装mysql5.7后,允许远程登录
    1、在mysql的配置文件中设置bind-address=0.0.0.0 2、在databasemysql中设置root用户的host为% 安装deb后使用apt-cachepolicymysql-server查看......
  • 界面控件DevExtreme DataGrid——一个多用途的UI组件
    DevExtreme拥有高性能的HTML5/JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NETCore,jQuery,Knockout等)构建交互式的Web应用程序,该套件附带功能......
  • vue组件介绍及应用
    一个.vue文件就是一个组件组件都是由三部分组成:html结构(html结构都是在template标签中)、js逻辑、css样式1)template只能解析一个根标签2)js逻辑都是在script标签中,必须设......
  • pyqt5图书管理系统--2、登录页面设计
    紧接注册页面设计;登录页面设计也是图书管理系统其中的一个模块,模块代码结构如下:    导入的模块importsysfromPyQt5.QtWidgetsimport*importqdarkstylefromP......
  • element-ui表格组件的封装
    背景我们平常工作中需要用表格的形式来展示多行数据需求需求1:通过配置文件的形式来设置表格的列需求2:可以合并表头代码MyTable.vue<template><div><el-tabl......
  • ASP.NET Core缓存Redis最佳实践+分布式Session+单点登录(SSO)
    《ASP.NETCore分布式缓存RedisLock分布锁最佳实践》1、JMeter模拟高并发工具简单入门使用2、redis分布式锁介绍3、高并发扣减库存带来的问题与思考4、netcore基于StackE......
  • vue3.0 父组件显示子组件中的echarts,同时保证宽高自适应。
    目录vue3.0父组件显示子组件中的echarts,同时保证宽高自适应。el-card控件中的echarts进行填充布局示例代码vue3.0父组件显示子组件中的echarts,同时保证宽高自适应。父......
  • 基于Qt的桌面客户端组件化框架DT 开源啦
    这个是本人在工作中基于QT开发的组件化桌面开发框架,目前打算开源出来提供给大家,节省大家的开发时间和效率,希望对大家的开发有所帮助,也欢迎提出意见和改进建议1.为什么开源D......
  • 组件注册
    全局注册: Vue.component("my-aa",{data:function(){return{aa:"123",......