• SpringBoot2 +vue2 + shiro 集成山东通 auth2 方式单点登陆


    1.前言:

    最近在做一个基于SpringBoot 2 + shiro +vue2 项目集成山东通采用Auth2 的方式进行单点登陆。里面很多坑,在此总结记录一下,方便以后查阅。

    应用服务器互联网区、山东通接口在政务外网区、前置机在政务外网区,可以访问应用服务器。需要在前置机上配置端口转发

    单点登陆流程:
    在这里插入图片描述

    在这里插入图片描述
    用户通过山东通客户端访问系统。
    1、应用系统调用6.3获取授权码(code)接口获取用户访问临时授权码;
    2、应用系统调用6.2获取令牌(token)接口获取应用访问令牌;
    3、应用系统使用6.2获取的访问令牌和6.3获取的授权码获取统一用户编码,接口对应的是6.4获取登录用户统一用户编码接口;
    4、应用系统使用6.4获取的统一用户编码调用6.5获取用户信息接口获取用户的详细信息(包括手机号码)
    6、应用系统使用6.5获取的用户手机号码调用手机号码登录接口实现用户登录;

    2.配置步骤

    2.1 SpringBoot2 后台配置

    1. 新增SdtSsoToken 实现AuthenticationToken

    package com.dechnic.omsdc.server.admin.shiro.sdtSso;/**
     * @className: SdtSsoToken
     * @author: houqd
     * @date: 2022/11/8
     **/
    
    import lombok.*;
    import org.apache.shiro.authc.AuthenticationToken;
    
    /**
     *@description:
     *@author:houqd
     *@time: 2022/11/8 13:40
     *
     */
    //@Data
    //@AllArgsConstructor
    //@RequiredArgsConstructor
    //@NoArgsConstructor
    public class SdtSsoToken implements AuthenticationToken {
       
    //    @NonNull
        private String code;
    //    @NonNull
        private String accessToken;
    
        private String principal;
    
        public SdtSsoToken( String code,  String accessToken) {
       
            this.code = code;
            this.accessToken = accessToken;
        }
    
        public String getCode() {
       
            return code;
        }
    
        public String getAccessToken() {
       
            return accessToken;
        }
    
        @Override
        public Object getPrincipal() {
       
            return principal;
        }
    
        public void setPrincipal(String principal) {
       
            this.principal = principal;
        }
    
        @Override
        public Object getCredentials() {
       
            return code;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    必坑1: 此处不要使用lombok 注解,使用后登陆验证的时候principle 为null ,验证失败。

    2. 新增 SdtSsoRealm 继承 AuthorizingRealm

    package com.dechnic.omsdc.server.admin.shiro.sdtSso;/**
     * @className: SdtSsoRealm
     * @author: houqd
     * @date: 2022/11/8
     **/
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.dechnic.omsdc.server.admin.entity.TSysPerm;
    import com.dechnic.omsdc.server.admin.entity.TSysRole;
    import com.dechnic.omsdc.server.admin.entity.TSysUser;
    import com.dechnic.omsdc.server.admin.service.TSysRoleService;
    import com.dechnic.omsdc.server.admin.service.TSysUserService;
    import com.dechnic.omsdc.server.common.entity.SsoUserBind;
    import com.dechnic.omsdc.server.common.mapper.SsoUserBindMapper;
    import com.dechnic.omsdc.server.common.service.ISdtSsoApiService;
    import com.dechnic.omsdc.server.common.utils.LightWeightEncoder;
    import com.dechnic.omsdc.server.common.utils.SpringContextUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.utils.URIBuilder;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    /**
     *@description:
     *@author:houqd
     *@time: 2022/11/8 13:52
     *
     */
    @Slf4j
    public class SdtSsoRealm extends AuthorizingRealm {
       
        private static final String DEFAULT_CHARSET = "UTF-8";
    
        @Autowired
        private SdtSsoConfigProps sdtSsoConfigProps;
        @Autowired
        TSysUserService tSysUserService;
        @Resource
        SsoUserBindMapper ssoUserBindMapper;
        @Autowired
        private TSysRoleService roleService;
        @Autowired
        private ISdtSsoApiService sdtSsoApiService;
    
        @Override
        public boolean supports(AuthenticationToken token) {
       
            return token instanceof SdtSsoToken;
        }
    
        // 获取授权信息
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
       
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            TSysUser user = (TSysUser) principals.getPrimaryPrincipal();
            List<TSysRole> roleList = user.getRoleList();
            if (roleList == null || roleList.size() == 0) {
       
                roleList = roleService.getUserRoleInfo(user.getId(), TSysPerm.PERM_TYPE.MENU);
                if(roleList == null || roleList.size()==0){
       
                    throw new AuthenticationException(user.getUserName()+"尚未分配角色,请联系管理员!");
                }
                user.setRoleList(roleList);
            }
    
            for (TSysRole role : roleList) {
       
                authorizationInfo.addRole(role.getRoleName());
                for (TSysPerm perm : role.getPermList()) {
       
                    if (StringUtils.isNotEmpty(perm.getPermName())) {
       
                        authorizationInfo.addStringPermission(perm.getPermName());
                    }
                }
            }
            return authorizationInfo;
        }
    
        // 获取身份验证相关信息
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
       
            SdtSsoToken sdtSsoToken = (SdtSsoToken) token;
            String accessToken = sdtSsoToken.getAccessToken();
            String code = sdtSsoToken.getCode();
            String ssoUserId = this.sdtSsoApiService.getSsoUserId(accessToken, code);
            String ssoUserPhoneNo = this.sdtSsoApiService.getSsoUserPhoneNo(accessToken, ssoUserId);
            TSysUser user = getTsysUserBySsoUserId(ssoUserPhoneNo);
    
            List<TSysRole> roleList = user.getRoleList();
            if (roleList == null || roleList.size() == 0) {
       
                roleList = roleService.getUserRoleInfo(user.getId(), TSysPerm.PERM_TYPE.MENU);
                if(roleList == null || roleList.size()==0){
       
                    throw new AuthenticationException(user.getUserName()+"尚未分配角色,请联系管理员!");
                }
                user.setRoleList(roleList);
            }
            if (user == null) {
       
                throw new UnknownAccountException("用户名或密码错误!");
            }
            if (user.getState() == TSysUser.STATE.INVALID) {
        // 账户冻结
                throw new LockedAccountException("账号已被锁定,请联系管理员");
            }
            SimpleAuthenticationInfo authenticationInfo =
                    new SimpleAuthenticationInfo(user, code, getName());
            return authenticationInfo;
        }
    
    
    
        private TSysUser getTsysUserBySsoUserId(String ssoUserID) {
       
            TSysUser user = null;
            SsoUserBind ssoUserBind = ssoUserBindMapper.selectBySSoUserId(ssoUserID);
            if (ssoUserBind != null){
       
                user = this.tSysUserService.selectById(ssoUserBind.getOmdsUserId());
                List<TSysRole> roleList = user.getRoleList();
                if (roleList == null || roleList.size() == 0) {
       
                    roleList = roleService.getUserRoleInfo(user.getId(), TSysPerm.PERM_TYPE.MENU);
                    user.setRoleList(roleList);
                }
            }
            return user;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149

    3. ShiroConfig 配置

    package com.dechnic.omsdc.server.admin.shiro;
    
    import com.dechnic.omsdc.server.admin.shiro.oauth2.client.OAuth2Realm;
    import com.dechnic.omsdc.server.admin.shiro.sdtSso.SdtSsoRealm;
    import com.dechnic.omsdc.server.admin.shiro.sdtSso.SdtSsoToken;
    import com.dechnic.omsdc.server.admin.shiro.zyoaSso.ZyoaSsoRealm;
    import com.dechnic.omsdc.server.common.utils.SpringContextUtil;
    import lombok.extern.slf4j.Slf4j;
    import net.sf.ehcache.CacheManager;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
    import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
    import org.apache.shiro.cache.CacheException;
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.io.ResourceUtils;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.mgt.SessionsSecurityManager;
    import org.apache.shiro.realm.Realm;
    import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
    import org.apache.shiro.session.mgt.SessionManager;
    import org.apache.shiro.session.mgt.eis.SessionDAO;
    import org.apache.shiro.spring.LifecycleBeanPostProcessor;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.CookieRememberMeManager;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.apache.shiro.web.servlet.SimpleCookie;
    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.DependsOn;
    import org.springframework.web.filter.DelegatingFilterProxy;
    import org.springframework.web.servlet.HandlerExceptionResolver;
    
    import javax.servlet.Filter;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    @Configuration
    @Slf4j
    public class ShiroConfig {
       
      private static long globalSessionTimeOut = -1000L;
      @Value("${prop.clientAddress}")
      private String clientAddress;
      /**
       * @description:@RequiresPermissions这类shiro权限的注解, 是DefaultAdvisorAutoProxyCreator这个bean设置之后才会生效的
       * @params:
       * @return:
       * @author: houqd
       * @time: 2020/1/30 17:20
       */
      @Bean
      public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
       
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator =
                new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
      }
    
      /**
       * 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;
       *
       * @param securityManager
       * @return
       */
      @Bean
      public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
       
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
      }
      /**
       * 自定义安全域,用户验证、权限等数据在此提供
       *
       * @return
       */
    
      @Bean
      public RealmUserName myShiroRealm() {
       
        RealmUserName realmUserName = new RealmUserName();
        realmUserName.setCredentialsMatcher(hashedCredentialsMatcher());
        return realmUserName;
      }
    
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
  • 相关阅读:
    Python也可以实现Excel中的“Vlookup”函数
    Linux操作系统 - 进程控制
    Springboot礼品商城系统设计与实现q92av计算机毕业设计-课程设计-期末作业-毕设程序代做
    BIO剖析
    Dart(2)-变量
    Leetcode 984. 不含 AAA 或 BBB 的字符串(网友思路)
    学生python编辑1--慢慢变大的小球
    C++对象模型(6)-- 数据语义学:继承的对象布局(含虚函数)
    前端如何防止数据被异常篡改并且复原数据
    JAVA面试中的SSM框架基础面试题
  • 原文地址:https://blog.csdn.net/u014212540/article/details/127807321