Spring整合Shiro,SSM整合Shiro例子

1 pom.xml 文件添加依赖

<!-- shiro集成 -->
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-core</artifactId>
	<version>${shiro.version}</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-web</artifactId>
	<version>${shiro.version}</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>${shiro.version}</version>
</dependency>

 

2 web.xml 文件添加shiro过滤器

<!-- shiro过滤器 -->
<filter>
	<filter-name>shiroFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	<init-param>
		<param-name>targetFilterLifecycle</param-name>
		<param-value>true</param-value>
	</init-param>
</filter>
<!-- shiro的filter-mapping-->
<filter-mapping>
	<filter-name>shiroFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

 

3 spring-shiro.xml spring整合shiro配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">

    <!-- 导入数据库的相关配置 -->
    <!--<import resource="classpath:spring/spring-mybatis.xml"/>-->

    <!--自定义过滤器******-->
    <bean id="loginFilter" class="com.battery.filter.LoginFilter"></bean>
    <bean id="myPermFilter" class="com.battery.filter.PermsFilter"></bean>


    <!-- 对应于web.xml中配置的那个shiroFilter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全接口,这个属性是必须的 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
        <!--<property name="loginUrl" value="/"/>-->
        <!-- 登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码) -->
        <!-- <property name="successUrl" value="/" ></property> -->
        <!-- 用户访问未对其授权的资源时,所显示的连接 -->
        <!--<property name="unauthorizedUrl" value="/error/unauthorized"/>-->

        <property name="filterChainDefinitions">
            <value>
                <!--首页,登录,登出不需要验证,其他的都需要验证-->
                /=anon
                /backStage/admin/login.action=anon
                <!--/adminUser/logout=anon-->
                <!--/adminUser/logout=anon-->

                <!-- 需要授权的url -->
                <!--/backStage/role/*.action = myPerm["1"]-->
                /backStage/admin/*.action = myPerm["13"]

                <!--&lt;!&ndash;不要使用/**=authc 因为,如果设置了,他就会跳到login.jsp这个登录页面&ndash;&gt;-->
                <!--&lt;!&ndash;/**=loginFilter&ndash;&gt;-->
                /backStage/**=loginFilter

                <!-- "id":"13" -->
                <!-- "permissionName": "开放管理员权限 "-->

            </value>

        </property>
        <property name="filters">
            <map>
                <!--自定义过滤器******-->
                <entry key="loginFilter" value-ref="loginFilter"/>
                <entry key="myPerm" value-ref="myPermFilter"/>
            </map>
        </property>

    </bean>

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>
    <!-- 数据库保存的密码是使用算法加密的,所以这里需要配置一个密码匹配对象 -->
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="md5"/>
        <property name="hashIterations" value="3"/>
        <property name="storedCredentialsHexEncoded" value="true"/>
    </bean>
    <!-- 缓存管理 -->
    <bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"></bean>

    <!--
    使用Shiro自带的JdbcRealm类
    指定密码匹配所需要用到的加密对象
    指定存储用户、角色、权限许可的数据源及相关查询语句
    -->
    <!--<bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">-->
    <!--<property name="credentialsMatcher" ref="credentialsMatcher"></property>-->
    <!--<property name="permissionsLookupEnabled" value="true"></property>-->
    <!--<property name="dataSource" ref="dataSource"></property>-->
    <!--<property name="authenticationQuery"-->
    <!--value="SELECT password FROM admin_user WHERE userName = ?"></property>-->
    <!--<property name="userRolesQuery"-->
    <!--value="SELECT roleName from user_role left join role using(id) left join admin_user using(id) WHERE userName = ?"></property>-->
    <!--&lt;!&ndash;基于用户到权限的&ndash;&gt;-->
    <!--<property name="permissionsQuery"-->
    <!--value="SELECT permissionName FROM user_permission left join admin_user using(id) left join permission using(id) WHERE userName = ?"></property>-->
    <!--&lt;!&ndash;基于角色-权限的&ndash;&gt;-->
    <!--&lt;!&ndash;<property name="permissionsQuery"&ndash;&gt;-->
    <!--&lt;!&ndash;value="SELECT permissionName FROM role_permission left join role using(id) left join permission using(id) WHERE roleName = ?"></property>&ndash;&gt;-->

    <!--</bean>-->

    <!-- 項目自定义的Realm -->
    <bean id="shiroDbRealm" class="com.battery.realm.ShiroDbRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher"></property>
        <!-- 启用身份验证缓存,即缓存AuthenticationInfo信息,默认false -->
        <!--<property name="cachingEnabled" value="false"/>-->
        <!--<property name="authenticationCachingEnabled" value="false"/>-->
        <!-- 缓存AuthenticationInfo信息的缓存名称 -->
        <!--<property name="authenticationCacheName" value="authenticationCache"/>-->
        <!-- 缓存AuthorizationInfo信息的缓存名称 -->
        <!--<property name="authorizationCacheName" value="authorizationCache"/>-->
        <property name="authorizationCachingEnabled" value="false"/>
        <property name="authenticationCachingEnabled" value="false"/>

    </bean>
    <!-- Shiro安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="shiroDbRealm"></property>
        <property name="cacheManager" ref="shiroCacheManager"></property>
    </bean>

    <!-- 开启shiro注解-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true"/>
    </bean>

    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

</beans>

 

4 ShiroDbRealm.java 自定义Realm类,用于登录信息比对和授权

/**
 * 自定义Realm
 *
 * @author ellen
 * @version 1.0
 * @date 2018/11/3
 */
public class ShiroDbRealm extends AuthorizingRealm {

    @Autowired
    IAdminService adminService;

    /**
     * Shiro权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //这里转化为String是因为传进来的时候也是String类型
        String userName = (String) principals.getPrimaryPrincipal();

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //这里返回的是权限的id不是权限的名字
        List<String> permIds = adminService.getPermissionIdByName(userName);
        info.setStringPermissions(new HashSet<String>(permIds));

        return info;
    }

    /**
     * Shiro登录认证(原理:用户提交 用户名和密码  --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ---- shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userName = token.getUsername();

        //从数据库中查找用户
        Admin admin = adminService.selectOne(new EntityWrapper<Admin>().eq("admin_name", userName));
        //账号不存在
        if (admin == null) {
            return null;
        }

        //这里传入正确的用户名跟密码,让shiro来比较
        return new SimpleAuthenticationInfo(admin.getAdminName(), admin.getAdminPassword(), getName());
    }

    /**
     * 清除用户认证信息
     *
     * @param principal
     */
    protected void clearCachedAuthenticationInfo(String principal) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(
                principal, getName());
        clearCachedAuthenticationInfo(principals);
    }

    /**
     * 清除所有用户授权信息缓存.
     */
    public void clearAllCachedAuthorizationInfo() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (cache != null) {
            for (Object key : cache.keys()) {
                cache.remove(key);
            }
        }
    }

}

 

5 LoginFilter.java 自定义登录过滤器,用于查看是否进行过登录认证

/**
 * AccessControlFilter是所有的URL都经过的过滤器
 * AuthorizationFilter是需要验证的url才经过的过滤器
 *
 * @author ellen
 * @version 1.0
 * @date 2018/11/3
 */
public class loginFilter extends AuthorizationFilter {

    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse response, Object o) throws Exception {
        //判断用户是否登录,如果登录,返回true ,如果没登录,就返回没有登录
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            return true;
        } else {
            //这句话的意思,是让浏览器用utf8来解析返回的数据
            response.setContentType("text/html;charset=UTF-8");
            //这句话的意思,是告诉servlet用UTF-8转码,而不是用默认的ISO8859
            response.setCharacterEncoding("UTF-8");

            PrintWriter writer = response.getWriter();
            writer.write(JSONObject.toJSONString(ResponseBean.createNoLogin("您未登录,请先登录!")));
            writer.close();

            return false;
        }
    }
}

 

6 PermsFilter.java 自定义权限过滤器,用于拦截需要授权的请求

/**
 * 自定义权限过滤器
 *
 * @author ellen
 * @version 1.0
 * @date 2018/11/3
 */
public class PermsFilter extends PermissionsAuthorizationFilter {

    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
        Subject subject = getSubject(request, response);
        if (!subject.isAuthenticated()) {
            //这句话的意思,是让浏览器用utf8来解析返回的数据
            response.setContentType("text/html;charset=UTF-8");
            //这句话的意思,是告诉servlet用UTF-8转码,而不是用默认的ISO8859
            response.setCharacterEncoding("UTF-8");

            PrintWriter writer = response.getWriter();
            writer.write(JSONObject.toJSONString(ResponseBean.createNoLogin("您未登录,请先登录!")));
            writer.close();

            return false;

        }

        String[] perms = (String[]) mappedValue;

        boolean isPermitted = true;
        if (perms != null && perms.length > 0) {
            if (perms.length == 1) {
                if (!subject.isPermitted(perms[0])) {
                    noPerm(request, response);
                    isPermitted = false;
                }
            } else {
                if (!subject.isPermittedAll(perms)) {
                    noPerm(request, response);
                    isPermitted = false;
                }
            }
        }

        return isPermitted;
    }

    /**
     * 无权限返回
     *
     * @param request
     * @param response
     * @throws IOException
     */
    private void noPerm(ServletRequest request, ServletResponse response) throws IOException {
        //这句话的意思,是让浏览器用utf8来解析返回的数据
        response.setContentType("text/html;charset=UTF-8");
        //这句话的意思,是告诉servlet用UTF-8转码,而不是用默认的ISO8859
        response.setCharacterEncoding("UTF-8");

        PrintWriter writer = response.getWriter();
        writer.write(JSONObject.toJSONString(ResponseBean.createNoPower("您无权限操作!")));
        writer.close();
    }
}

 

7 login请求方法,参考

/**
 * 管理员登录
 *
 * @param admin
 * @param request
 * @return
 */
@RequestMapping("/login")
public ResponseBean login(Admin admin, HttpServletRequest request) {
	if (StringUtil.isEmpty(admin.getAdminName()) || StringUtil.isEmpty(admin.getAdminPassword())) {
		return ResponseBean.createError("用户名或密码不能为空");
	}

	UsernamePasswordToken token = new UsernamePasswordToken(admin.getAdminName(), admin.getAdminPassword());
	token.setRememberMe(false);
	Subject subject = SecurityUtils.getSubject();

	try {
		subject.login(token);
		//将用户存进session
		Admin currentAdmin = adminService.selectOne(new EntityWrapper<Admin>().eq("admin_name", admin.getAdminName()));
		request.getSession().setAttribute(SessionConst.LOGIN_ADMIN_SESSION_KEY, currentAdmin);

		return ResponseBean.createSuccess().setMessage("登录成功").addData("admin", admin);
	} catch (IncorrectCredentialsException e) {
		return ResponseBean.createError("登录密码错误. Password for account " + token.getPrincipal() + " was incorrect.");

	} catch (ExcessiveAttemptsException e) {
		return ResponseBean.createError("登录失败次数过多");

	} catch (LockedAccountException e) {
		return ResponseBean.createError("帐号已被锁定. The account for username " + token.getPrincipal() + " was locked.");

	} catch (DisabledAccountException e) {
		return ResponseBean.createError("帐号已被禁用. The account for username " + token.getPrincipal() + " was disabled.");

	} catch (ExpiredCredentialsException e) {
		return ResponseBean.createError("帐号已过期. the account for username " + token.getPrincipal() + "  was expired.");

	} catch (UnknownAccountException e) {
		return ResponseBean.createError("帐号不存在. There is no user with username of " + token.getPrincipal());

	} catch (UnauthorizedException e) {
		return ResponseBean.createError("您没有得到相应的授权!" + e.getMessage());
	}

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值