Shiro整合SSO单点登录系统

前言

shiro是一个非常强大的权限管理框架,关于shiro与cas整合的示例有很多,但是我们平时开发的时候,很多公司并不是使用cas来做SSO的,而是自己公司会用自己开发的。本文就主要针对这种方式的整合。

新增SSO相关的properties

#sso服务器登录地址,service参数表示登录成功后要跳转的地址
ssoServiceUrl=http://www.authserver.com/auth/login?service=http://www.client.com/user/login

#sso的token的校验地址
tokenValidateUrl=http://www.authserver.com:9999/auth/validatetoken

#应用名称标识
microServiceId=app

#redis相关信息
JedisUrl=198.168.1.101
JedisPort=6379
JedisPassword=666666

修改spring-shiro.xml

<bean id="shiroSecurityFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
   <property name="securityManager" ref="securityManager" />
   <property name="loginUrl" value="${ssoServiceUrl}" />
   <!-- <property name="successUrl" value="/user/index" /> -->
   <property name="filters">
           <map>
               <entry key="authc" value-ref="ssoFilter"/>
           </map>
   </property>
   <property name="filterChainDefinitions">
      <value>
         /kaptcha.jpg=anon
         /assets/** = anon
         /images/** = anon
         /javascripts/** = anon
         /stylesheets/** = anon
         /user/login = anon
         /httpserver/* = anon
         /** = authc
      </value>
   </property>
</bean>
<bean id="ssoFilter" class="com.demo.web.sso.SSOFilter"/>

自定义ssoFilter

/**
 * sso自定义过滤器
 */
public class SSOFilter implements Filter{

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        {
            HttpServletRequest request = (HttpServletRequest)servletRequest;
            HttpServletResponse response = (HttpServletResponse)servletResponse;
            String token = request.getParameter("token");
            PropertiesTool propertiesTool = PropertiesTool.getInstance();
            String ssoServiceUrl = propertiesTool.getValue("ssoServiceUrl");
            String tokenValidateUrl = propertiesTool.getValue("tokenValidateUrl");
            if(null == token) {
                Cookie cookie = CookieUtil.getCookieByName(request, "token");
                if(null != cookie) {
                    token = cookie.getValue();
                }
            }
            if(null == token) {
                //没有token,重定向至sso server登录页
                response.sendRedirect(ssoServiceUrl);
            }else {
                String urlString = request.getRequestURI();
                if(urlString.endsWith("/logout")) {
                    String JedisUrl = propertiesTool.getValue("JedisUrl");
                    String JedisPort = propertiesTool.getValue("JedisPort");
                    Jedis jedis = new Jedis(JedisUrl, Integer.parseInt(JedisPort));
                    jedis.del(token.getBytes());
                    jedis.close();
                    SecurityUtils.getSubject().logout();
                    response.sendRedirect(ssoServiceUrl);//重定向至sso server登录页
                    return;
                }

                //有token,去sso server验证token的有效性
                Map<String, String> map = new HashMap<>();
                map.put("token", token);
                String result = HttpClientUtil.doGet(tokenValidateUrl, map);
                if(StringUtils.isNotBlank(result)){//验证成功,跳转至首页,并从redis中获取权限
                    SystemSession.setUser(SSOTokenUtil.getToken(request));//设置系统session(把用户信息保存在ThreadLocal中)
                    Cookie cookie = new Cookie("token", token);
                    cookie.setPath("/");
                    response.addCookie(cookie);
                    filterChain.doFilter(request, response);
                } else{
                    response.sendRedirect(ssoServiceUrl);//验证失败,重定向至sso server登录页
                }
            }
        }
    }


    public void destroy() {

    }

自定义shiro的realm

在spring-shiro.xml中添加:

<bean id="myRealm" class="com.demo.web.realm.MyRealm"/>
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myRealm" />
    </bean>

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    <bean
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
    </bean>

realm类:

public class MyRealm extends AuthorizingRealm{

    public MyRealm() {
        setName("myRealm");
        HashedCredentialsMatcher hcm = new HashedCredentialsMatcher();
        //使用SHA-512 加密
        hcm.setHashAlgorithmName(Sha512Hash.ALGORITHM_NAME);
        setCredentialsMatcher(hcm);
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        SysUser user = SystemSession.getUser();
        if (user != null) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            List<Menu> list = user.getRoles().get(0).getMenuList();
            for (Menu menu : list){
                if (StringUtils.isNotBlank(menu.getPermission())) {
                    // 添加基于Permission的权限信息
                    for (String permission : StringUtils.split(menu.getPermission(),",")){
                        info.addStringPermission(permission);
                    }
                }
            }
            // 添加用户权限
            info.addStringPermission("user");
            // 添加用户角色信息
            for (SysRole role : user.getRoles()) {
                info.addRole(role.getEnglishName());
            }
            return info;
        } else {
            return null;
        }
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {
        //获取user信息
        SysUser user = SystemSession.getUser();
        if (user != null) {
            if (user.getIsEnable()!=1) {
                throw new AuthenticationException("msg:该帐号已禁止登录.");
            }
            return new SimpleAuthenticationInfo(new Principal(user), Constants.CREDENTIALS, getName());
        }
        return null;
    }


    public static class Principal implements Serializable {

        private static final long serialVersionUID = 1L;

        private String id; // 编号
        private String loginName; // 登录名
        private String name; // 姓名
        private List<String> roleIdList;


        public List<String> getRoleIdList() {
            return roleIdList;
        }

        public void setRoleIdList(List<String> roleIdList) {
            this.roleIdList = roleIdList;
        }

        public Principal(SysUser user) {
            this.id = user.getId();
            this.loginName = user.getUsername();
            this.name = user.getCharacterName();
            this.roleIdList=user.getRoleIdList();
        }

        public String getId() {
            return id;
        }

        public String getLoginName() {
            return loginName;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return id;
        }

    }

}

由于shrio权限要做登录校验,但我们的登录已交给sso处理,这里只需要保证shiro的前后校验能通过就行,把password改成常量,并取消原来的加盐。CREDENTIALS=”6bf968f0c7b39ddbb7c8aa836b74d092060ed9b85b620a7fb088ecc48c6b3efd696bbd820f74c14f66c80c86c557c4bfda51b8a3743d3d568cc5c08410b7bb6a”;

修改index

@RequestMapping("index")
public String index(ModelMap model, String mainFrame, HttpServletRequest request) {
       SysUser currentUser = SSOTokenUtil.getToken(request);
   List<Menu> menus = currentUser.getRoles().get(0).getMenuList();
   List<Menu> sysMenus = new ArrayList<>();
   for(Menu menu : menus){
      if(currentUser.getRemarks().equals(menu.getSysCode())){
         sysMenus.add(menu);
      }
   }
   //设置用户登录信息
   UsernamePasswordToken token = new UsernamePasswordToken(
         currentUser.getUsername(), Constants.PASSWORD);
   SecurityUtils.getSubject().login(token);
   model.addAttribute("menus", sysMenus);
   model.addAttribute("currentUser", currentUser);

   return "index";
}

PASSWORD= “lvadmin”,是CREDENTIALS对应的明文。

文中所用到的一些SSOFilter,SystemSession,SSOTokenUtil等原码,以附件的形式提供下载。
Shiro整合SSO单点登录系统工具类下载

猜你喜欢

转载自blog.csdn.net/m0_37797991/article/details/78529096