zoukankan      html  css  js  c++  java
  • cas的单点登录实现

    1.  前提条件

    环境:jdk1.8、shiro1.4.0及以上版本、项目以 spring+shiro构建

    工具:buji-pac4j-3.1.0-jar-with-dependencies.jar以及相关配置文件

    从网上下载cas项目源码

    client为客户端代码,server为服务端代码。

    将buji-pac4j-3.1.0导入eclipse,eclipse须装Maven插件,项目右键:

    Run As --> Run Configurations

    打开弹窗,Name一栏填buji-pac4j-3.1.0-jar-with-dependencies,

    Base directory一栏选择buji-pac4j-3.1.0的路径,

    Goals一栏填package,点击Run即可生成buji-pac4j-3.1.0-jar-with-dependencies.jar

    2.  导入相关文件

    在项目的WEB-INF的lib下导入buji-pac4j-3.1.0-jar-with-dependencies.jar.

        引入cas.properties(在编译器中请放在resources下,tomcat中放在WEB-INF的class下)。

    3.  修改相关联的配置文件。

    1. 修改web.xml增加context-param

    <!--本地登录开关-->
    <context-param>
        <param-name>pac4jConfigLocation</param-name>
        <param-value>classpath:cas.properties</param-value>
    </context-param>

    1. 修改web.xml增加listener

    <listener>
        <listener-class>io.buji.pac4j.extension.listener.Pac4jServletContextListener</listener-class>
    </listener>

    放在Spring容器加载之后例如:

    <!-- 加载Spring容器配置  -->
    <listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <listener>
           <listener-class>io.buji.pac4j.extension.listener.Pac4jServletContextListener</listener-class>
       </listener>

    4  在shiro中追加相关配置

         <!--追加 start-->
    <bean id="annotationProxy"
          class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>

    <bean id="casRealm" class="io.buji.pac4j.extension.realm.SSOCasRealm">
        <property name="cachingEnabled" value="false" />
        <property name="authenticationCachingEnabled" value="false" />
        <property name="authenticationCacheName" value="authenticationCache" />
        <property name="authorizationCachingEnabled" value="false" />
        <property name="authorizationCacheName" value="authorizationCache" />
    </bean>
    <!--追加 end-->

       depends-on 需要Shiro生命周期处理器的id。例如:

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

       depends-on 需要的这个bean的id。

    自定义casRealm实现认证和授权

    <bean id="casRealm" class="io.buji.pac4j.extension.realm.SSOCasRealm">
        <property name="cachingEnabled" value="false" />
        <property name="authenticationCachingEnabled" value="false" />
        <property name="authenticationCacheName" value="authenticationCache" />
        <property name="authorizationCachingEnabled" value="false" />
        <property name="authorizationCacheName" value="authorizationCache" />
    </bean>

           请继承Pac4jRealm,bean的ID不要变例如:


    public class Pac4jRealm extends io.buji.pac4j.realm.Pac4jRealm {

        @Autowired
        private UserService userService;
        private String principalNameAttribute;

        @Autowired
        protected UserRoleService userRoleService;
        @Autowired
        protected OrganizationRoleService organizationRoleService;
        @Autowired
        protected ModuleService moduleService;
        @Autowired
        protected UserCasService userCasService;

        // 是否启用超级管理员
        protected boolean activeRoot = true;

        public String getPrincipalNameAttribute() {
            return this.principalNameAttribute;
        }

        public void setPrincipalNameAttribute(String principalNameAttribute) {
            this.principalNameAttribute = principalNameAttribute;
        }

        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            Pac4jToken token = (Pac4jToken)authenticationToken;
            LinkedHashMap<String, CommonProfile> profiles = token.getProfiles();
            String username = profiles.get("SSOCasClient").getId();
            User user = userService.getByUsername(username);
            ShiroUser shiroUser = new ShiroUser(user.getId(), user.getUsername(), user);

            Object credentials = token.getCredentials();
           
            return new SimpleAuthenticationInfo(shiroUser,credentials,getName());
        }


        /**
         *
    授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
         */
       
    @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
        {
            Collection<?> collection = principals.fromRealm(getName());
            if (Collections3.isEmpty(collection))
            {
                return null;
            }
            ShiroUser shiroUser = (ShiroUser)collection.iterator().next();

           /* SimplePrincipalCollection collection =(SimplePrincipalCollection) principals.getPrimaryPrincipal();
            String userName =(String) collection.getPrimaryPrincipal();
            User user = userService.getByUsername(userName);*/

            List<UserRole> userRoles = userRoleService.find(shiroUser.getId());
            List<OrganizationRole> organizationRoles =
                    organizationRoleService.find(shiroUser.getUser().getOrganization().getId());
            //ShiroUser shiroUser = new ShiroUser(user.getId(), user.getUsername(), user);
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.addStringPermissions(makePermissions(userRoles, organizationRoles, shiroUser));

            return info;
        }

        private Collection<String> makePermissions(List<UserRole> userRoles, List<OrganizationRole> organizationRoles,
                                                   ShiroUser shiroUser)
        {
            // 是否启用超级管理员
            if (activeRoot)
            {
                // 为超级管理员,构造所有权限
                if (userCasService.isSupervisor(shiroUser.getId()))
                {
                    Collection<String> stringPermissions = Sets.newHashSet();

                    List<Module> modules = moduleService.findAll();
                    for (Module module : modules)
                    {
                        List<Permission> permissions = module.getPermissions();
                        // 默认构造CRUD权限
                        stringPermissions.add(module.getSn() + ":" + Permission.PERMISSION_CREATE);
                        stringPermissions.add(module.getSn() + ":" + Permission.PERMISSION_READ);
                        stringPermissions.add(module.getSn() + ":" + Permission.PERMISSION_UPDATE);
                        stringPermissions.add(module.getSn() + ":" + Permission.PERMISSION_DELETE);

                        for (Permission permission : permissions)
                        {
                            stringPermissions.add(module.getSn() + ":" + permission.getShortName());
                        }
                    }

                    //log.info("使用了超级管理员:" + shiroUser.getLoginName() + "登录了系统。At " + new Date());
                    //log.info(shiroUser.getLoginName() + "拥有的权限:" + stringPermissions);
                    return stringPermissions;
                }
            }

            Set<Role> roles = Sets.newHashSet();
            for (UserRole userRole : userRoles)
            {
                roles.add(userRole.getRole());
            }

            for (OrganizationRole organizationRole : organizationRoles)
            {
                roles.add(organizationRole.getRole());
            }

            Collection<String> stringPermissions = Sets.newHashSet();
            for (Role role : roles)
            {
                List<RolePermission> rolePermissions = role.getRolePermissions();
                for (RolePermission rolePermission : rolePermissions)
                {
                    Permission permission = rolePermission.getPermission();
                    stringPermissions.add(permission.getModule().getSn() + ":" + permission.getShortName());
                }
            }

            //    log.info(shiroUser.getLoginName() + "拥有的权限:" + stringPermissions);
            return stringPermissions;
        }



    }

          可以直接仿造自己项目中的realm写,不一定要按照以上的Demo写。

    5 修改cas.properties

    ##cas服务前缀
    sso.cas.server.prefixUrl=http://127.0.0.1:8081/cas
    ##cas服务登录url
    sso.cas.server.loginUrl=http://127.0.0.1:8081/cas/login

    ##cas客户端回调地址
    sso.cas.client.callbackUrl=http://127.0.0.1:8080/dts/callback?client_name=SSOCasClient
    ##cas服务端成功跳转地址
    sso.cas.client.successUrl=http://127.0.0.1:8080/dts/index

    ##cas登出地址
    sso.cas.client.logoutUrl=http://127.0.0.1:8081/cas/logout


    ##本地登录地址
    sso.cas.client.nativeLoginUrl=http://127.0.0.1:8080/dts/login

    ##securityManagerId
    securityManagerId=securityManager

    ##shiro配置filterChainDefinitions中定义的logout
    logoutUrl=/logout

    ##shiro配置filterChainDefinitions中的最后一个匿名访问地址
    lastAnonUrl =/zui*/**

    ##shiro配置的org.apache.shiro.spring.web.ShiroFilterFactoryBean的id
    originFilter=shiroFilter

    ##pac4j配置的org.apache.shiro.spring.web.ShiroFilterFactoryBean的id
    ssoFilter=myfilter

    ##是否启用开关
    #1只能单点登录  0全开启 -1 只能本地登录
    loadFlag =1

    这个Demo使用的cas服务端的登录地址为:http://127.0.0.1:8081/cas/login

    以上属性名不要改变,只配置属性值,ssoFilter这个属性不用配置

    6 服务端打war包及部署。

     在IDEA里导入服务端项目casservercas-4.2.1,

    用Gradle插件刷新显示所有子项目,找到cas-server-webapp,

    点开cas-server-webapp --> Tasks --> build,先点击clean再点击war,

    等待运行结束,在cas-server-webapp项目下build下libs里生成了war包。

    将war包部署至服务器,访问该项目即可。

    7 常见问题解决。

    1.项目部署之后, One or more listeners failed to start. Full details will be found in the appropriate container log file。

    这个问题一般来是jar包冲突或版本不对。常见的就是Shiro的jar包版本过低。请升级到1.4或以上版本。还有一种情况,guava版本不同,可以尝试下,删除buji-pac4j-3.1.0-jar-with-dependencies.jar中的com文件夹。(删除前请备份。)

  • 相关阅读:
    HDU 1028 简单动态规划
    poj2250 动态规划+路径标记
    计算机网络你还懵逼吗?第二弹biubiubiu
    几款值得推荐的android(安卓)开源框架简介
    Android Studio安装更新终极解决方式
    个人开发者做一款Android App需要知道的事情
    Android webservice的用法详细讲解
    Android图片加载与缓存开源框架:Android Glide
    进入社会看到的一片总结,若有感慨
    Android 开源组件 ----- Android LoopView无限自动轮转控件
  • 原文地址:https://www.cnblogs.com/zhncnblogs/p/10950420.html
Copyright © 2011-2022 走看看