Spring集成Shiro

在上一篇文章已经详细介绍了Shiro的简介,以及简单的例子,有兴趣的朋友可以看一下我的上一篇文章  点击观看Shiro入门简介这篇文章主要讲解spirng怎么集成Shiro。

 

在集成之前在这里在先介绍下过滤器吧

securityManager:这个属性是必须的。

loginUrl :没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。

successUrl :登录成功默认跳转页面,不配置则跳转至”/”。如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。不跳转到此。

unauthorizedUrl :没有权限默认跳转的页面

 

其权限过滤器及配置释义

anon:例子/admins/**=anon 没有参数,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数

roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。

port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString

是你访问的url里的?后面的参数。

authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查

 

开始集成

1.添加maven依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.4.0</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>

2.在web.xml里面添加配置

  <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>
  <filter-mapping>
    <filter-name>shiRoFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

3.在spring.xml中添加配置

      <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- 自定义 realm -->
        <property name="realm" ref="myDbRealm"/>
    </bean>

    <!--管理ShiRo bean生命周期的-->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- spring 配置ini -->
    <bean id="shiRoFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <!--如果需要登录就跳转到 Login.jsp-->
        <property name="loginUrl" value="/Login.jsp"/>
        <!--如果没有权限就跳转 RoleError.jsp-->
        <property name="unauthorizedUrl" value="/RoleError.jsp"/>
        <!--配置shiRo过滤器-->
        <property name="filterChainDefinitions">
            <value>
            /Login.jsp = anon
            /LoginSuccess.jsp = authc
            /RoleSuccess.jsp = roles[role2]
            </value>
        </property>
    </bean>

其中,spring.xml 中的 shiRoFilter名字和 web.xml 文件中的 shiRoFilter是对应的,必须一致。

 

4.自定义实现的Realm

package cn.et.demo02.config;

import cn.et.demo02.mapper.UserInfoMapper;
import cn.et.demo02.model.UserInfoModel;
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 org.springframework.stereotype.Component;

import java.util.Set;

@Component
public class MyDbRealm extends AuthorizingRealm {
    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 获取当前用户的权限
     * 将当前用户在数据库的角色的权限 加载到AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String userName =principals.getPrimaryPrincipal().toString();
        Set<String> roleList =userInfoMapper.getRoleByUserName(userName);
//        Set<String> permsList =userMapper.queryPermsByName(userName);

        //角色和权限集合对象
        SimpleAuthorizationInfo sai =new SimpleAuthorizationInfo();
        sai.setRoles(roleList);
//        sai.setStringPermissions(permsList);
        return sai;
    }

    /**
     * 认证
     * 将登陆输入的用户名和密码跟数据库里面的用户名密码对比 是否相等
     * 返回值 null表示认证失败 非null认证通过
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //页面传入的token
        UsernamePasswordToken upt =(UsernamePasswordToken)token;
        UserInfoModel queryUser =userInfoMapper.getUserByUserName(token.getPrincipal().toString());

        if (queryUser !=null && queryUser.getPassword().equals(new String(upt.getPassword()))) {
            SimpleAccount sa =new SimpleAccount(upt.getUsername(),upt.getPassword(),"MyDbRealm");
            return sa;
        }
        return null;
    }
}

 

5.编写一个测试类

package cn.et.demo02.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("demo02")
public class ShiroController {

    @RequestMapping("login")
    public String login(String userName, String password){
        //获取当前的用户
        Subject currentUser =SecurityUtils.getSubject();

        //用户输入的用户名跟密码
        UsernamePasswordToken token = new UsernamePasswordToken(userName, password);

        try {
            currentUser.login( token );
            return "/LoginSuccess.jsp";
        } catch (UnknownAccountException uae) {
            System.out.println("用户名不存在:" + token.getPrincipal());
        } catch (IncorrectCredentialsException ice) {
            System.out.println("密码不正确!!");
        } catch (LockedAccountException lae) {
            System.out.println("用户已被锁定!!");
        }
        return "/LoginError.jsp";
    }
}

这个时候调用login方法他就会去自定义的类里面去进行认证、授权。但是这个时候过滤规则仍然是写死在xml文件中的 非常的不方便,所以这个时候我们可以自己来定义过滤规则。将spring的配置文件需要修改一下

修改前:

<!--配置shiRo过滤器-->
<property name="filterChainDefinitions">
    <value>
    /Login.jsp = anon
    /LoginSuccess.jsp = authc
    /RoleSuccess.jsp = roles[role2]
    </value>
</property>

改成:

        <!--配置 自定义 shiRo过滤器-->
        <property name="filters">
            <util:map>
                <entry key="filter" value-ref="myFilter"></entry>
            </util:map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /** = filter
            </value>
        </property>

 

自己实现一个过滤器 继承 AuthorizationFilter

package cn.et.demo02.config;


import cn.et.demo02.mapper.MenuMapper;
import cn.et.demo02.model.MenuModel;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

@Component
public class MyFilter extends AuthorizationFilter {
    @Autowired
    private MenuMapper menuMapper;
    /**
     * 匹配指定过滤器规则的url
     * @param regex
     * @param url
     * @return
     */
    public static boolean matchUrl(String regex,String url){
        regex=regex.replaceAll("/+", "/");
        if(regex.equals(url)){
            return true;
        }
        regex=regex.replaceAll("\\.", "\\\\.");
        // /login.html  /l*.html
        regex=regex.replaceAll("\\*", ".*");
        // /**/login.html  /a/b/login.html
        if(regex.indexOf("/.*.*/")>=0){
            regex=regex.replaceAll("/\\.\\*\\.\\*/", "((/.*/)+|/)");
        }
        System.out.println(regex+"----"+url);
        return Pattern.matches(regex, url);
    }

    /**
     * isAccessAllowed用于判断当前url的请求是否能验证通过  如果验证失败 调用父类的onAccessDenied决定跳转到登录失败页还是授权失败页面
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)throws Exception {
        HttpServletRequest req=(HttpServletRequest)request;

        //获取用户访问的资源路径
        String url=req.getRequestURI();

        //获取哪些url需要哪些认证
        List<MenuModel> list = menuMapper.getMenuByUrl(url);

        //数据库没有配置当前url的授权
        if (list.size()==0) {
            return false;
        }

        String urlAuth=null;
        for (MenuModel menu : list) {
            if (matchUrl(menu.getUrl(), url)) {
                urlAuth =menu.getFilter();
            }
        }

        if(urlAuth==null){
            return false;
        }
        //配置的过滤器是anon 直接放过
        if(urlAuth.startsWith("anon")){
            return true;
        }
        //配置的是authc 判断当前用户是否认证通过
        Subject subject = getSubject(request, response);
        if(urlAuth.startsWith("authc")){
            return subject.isAuthenticated();
        }
        //授权认证 也需要判断是否登录 没有登录返回 登录继续下面的验证
        boolean ifAuthc=subject.isAuthenticated();

        if(!ifAuthc){
            return ifAuthc;
        }

        //如果是定义的roles过滤器  获取所有的roles 一般是roles[a,b]
        if(urlAuth.startsWith("roles")){
            String[] rolesArray=urlAuth.split("roles\\[")[1].split("\\]")[0].split(",");
            if (rolesArray == null || rolesArray.length == 0) {
                return true;
            }
            Set<String> roles = CollectionUtils.asSet(rolesArray);
            return subject.hasAllRoles(roles);
        }
        if(urlAuth.startsWith("perms")){
            String[] perms=urlAuth.split("perms\\[")[1].split("\\]")[0].split(",");
            boolean isPermitted = true;
            if (perms != null && perms.length > 0) {
                if (perms.length == 1) {
                    if (!subject.isPermitted(perms[0])) {
                        isPermitted = false;
                    }
                } else {
                    if (!subject.isPermittedAll(perms)) {
                        isPermitted = false;
                    }
                }
            }
            return isPermitted;
        }
        return false;
    }

}

 

以上就是spring集成shiro的全部配置,若有需要源码的可以给我留言。。。。。。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值