shiro与springMVC整合

注:该文基于springMVC已经配置好。

1. 架构预览

项目结构
这里写图片描述

shiro所需jar包
这里写图片描述

2. 整合shiro

2.1 配置web.xml

注意,由于shiro的主要作用就是拦截判断,所以我们不再需要springMVC的LoginInterceptorPermissionInterceptor拦截器了。其余的springMVC配置的代码保持不变。
在web.xml里添加shiroFilter:该过滤器名字将与spring.xml里注入的过滤器名字一致。所以当有请求时进了web.xml里时,请求就会被该过滤器转到spring.xml里的shiro过滤器。

<!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <!-- 设置true由servlet容器控制filter的生命周期 -->
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
    <!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean-->
    <init-param>
        <param-name>targetBeanName</param-name>
        <param-value>shiroFilter</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2.2 配置spring.xml

(本人将shiro的配置直接配在该文件下的,一般会新建一个shiro自己的配置文件,就像springMVC的springMVC-servlet.xml文件一样)

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login"/><!-- 如果不写的话,默认去找login.jsp页面 -->
        <property name="unauthorizedUrl" value="/index.jsp"/>   <!-- 认证不通过访问的页面 --> 
        <!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
        <property name="filterChainDefinitions">
            <value> 
                /refuse.jsp = anon
                /login.do = authc   <!-- anon过滤器表示没有权限也可访问login.do -->
                /logout.do = logout <!-- 表示访问logout.do时就直接访问logout这个过滤器,即直接退出 -->       
                /** = authc         <!-- 表示其他的所有路径都要通过认证后才能访问 -->
            </value>
        </property>

    </bean>

    <!-- 注入自定义realm -->
    <bean id="myShiroRealm" class="com.mvc.realm.MyShiroRealm">  
        <property name="accountService" ref="accountService" />  
    </bean>  

    <!-- 安全管理器 :必须注入-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
        <property name="realm" ref="myShiroRealm"></property>  
    </bean>  

    <!-- 注入查询用户名与密码的service实现类 -->
    <bean id="accountService" class="com.mvc.service.impl.AccountService"></bean>

securityManager:安全管理器。是必须注入的,所有的过滤都被它管理着。

loginUrl:没有登录时就会跳转到它指定的地址,如果不指定该属性,则会自动去找项目的根目录下的”/login.jsp”页面。

unauthorizedUrl:没有权限时默认的跳转路径。

filterChainDefinitions:过滤链。它可对路径进行过滤。如:
/refuse.jsp = anon anon过滤器表示认证不通过也可访问,所以这句代码表示refuse.jsp路径在没有登录时也可访问
/login.do = authc authc过滤器表示需要认证通过才可访问,也就是说login.do在没有登录时,是不能访问的,除非设为了loginUrl的值。

2.3 默认拦截器

过滤器简称

类名

解释

示例

1.认证过滤器

anon

org.apache.shiro.web.filter.authc.AnonymousFilter

可匿名访问。无参,一般用于过滤静态资源

/admins/**=anon 表示admins下的所有路径皆可匿名访问`

authc

org.apache.shiro.web.filter.authc.FormAuthenticationFilter

认证登录后才可访问。

/admins/user/**=authc

authc属性

usernameParam:表单提交的用户名参数名( username); passwordParam:表单提交的密码参数名(password); rememberMeParam:表单提交的密码参数名(rememberMe);

loginUrl:登录页面地址(/login.jsp);successUrl:登录成功后的默认重定向地址;

failureKeyAttribute:登录失败后错误信息存储key(shiroLoginFailure);

authcBasic

org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

http身分认证器。无参

/admins/user/**=authcBasic

authcBasic属性

applicationName:弹出登录框显示的信息(application);

user

org.apache.shiro.web.filter.authc.UserFilter

表示必须存在用户

/admins/user/**=user 表示身份认证通过或通过记住我认证通过的可以访问,此时进行登录操作不会做检查

logout

org.apache.shiro.web.filter.authc.LogoutFilter

退出拦截器

/logout.do=logout

主要属性

redirectUrl:退出成功后重定向的地址(/)

2.授权过滤器

perms

org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

权限授权过滤器。有参,多参时写成拼接字符串,各参之间以逗号分隔。多参时需每个权限都通过时才算通过,相当于hasAllRoles()

单参:/admins/user/**=perms[add] 表示该路径只有add权限时才可访问。多参:/admins/user/**=perms["add,delete"]

port

org.apache.shiro.web.filter.authz.PortFilter

端口过滤器

/admins/user/**=port[8080] 当端口号不是8080时会将访问url的端口改为8080后再跳转。

主要属性

port(80):指定可以通过的端口

roles

org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

角色授权过滤器,可多参

属性

loginUrl:登录页面地址;unauthorizedUrl:未授权后重定向的地址;

admins/user/**=roles[“admin,guest”] 多参时,都通过才算通过

rest

org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

请求方法拦截器(GET=read,POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create),它自动根据请求方法构建权限字符串。/admins/user/**=perms[user:post]会拼接“user:create”权限字符串

/users=rest[user],会自动拼出“user:read,user:create,user:update,user:delete”权限字符串进行权限匹配(所有都得匹配,isPermittedAll);

ssl

org.apache.shiro.web.filter.authz.SslFilter

安全协议拦截器,只有请求协议是https才能通过;否则自动跳转会https端口(443);其他和port拦截器一样;

/admins/user/**=ssl

2.4 自定义realm

此realm先不从数据库查询权限数据

/**** 
 * 自定义Realm 
 *  
 * @author Peter
 *  
 */  
public class MyShiroRealm extends AuthorizingRealm {  

    @Override
    public String getName() {
        return"customRealm";
    }


    // 支持什么类型的token
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    /*** 
     * 获取授权信息 
     */  
    @Override  
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {  

        //先自定义一个query权限,就不从数据库查询了 
        String username = (String) pc.fromRealm(getName()).iterator().next();  
        if (username != null) {  
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.addStringPermission("query");//权限
            return info;  
        }          
        return null;  
    }  
    /*** 
     * 获取认证信息 
     * 
     * 问题:如何在登录后不再进登录页面了呢???????????????????????????
     */  
    @Override  
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) {  
        UsernamePasswordToken token = (UsernamePasswordToken) at;  
        // 通过表单接收的用户名  
        // String username = token.getUsername();  
        String username = (String) at.getPrincipal();

        if (username != null && !"".equals(username)) {  
            User user = accountService.getUserByUserName(username); 
            if (user != null && user.getPassword().equals(new String(token.getPassword())) && user.getUsername().equals(token.getUsername())) {  
                return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());  
            }else{
                 //throw new UnknownAccountException(); //如果用户名错误 
                throw new IncorrectCredentialsException(); //如果密码错误 
            }
        }  

        return null;  
    }  

    /**用户的业务类**/  
    private IAccountService accountService;  

    public IAccountService getAccountService() {  
        return accountService;  
    }  

    public void setAccountService(IAccountService accountService) {  
        this.accountService = accountService;  
    }  

}  

2.5 登录

 /*** 
  * 提交数据的登录
  */  
 @RequestMapping(value = "login.do")  
 public String login(String username, String password,ModelMap model) {  
    Subject subject = SecurityUtils.getSubject(); 
    if(subject.isAuthenticated()){
        return "home.jsp";
    }else{
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);  
      String error = null;
      try {  
          subject.login(token);  
         // subject.logout();
      } catch (UnknownAccountException e) {  
          error = "用户名/密 错误";  
      } catch (IncorrectCredentialsException e) {  
          error = "用/密码 错误";  
      } catch (AuthenticationException e) {  
          //其他错误,比如锁定,如果想单独处理请单独catch处理  
          error = "其他错误:" + e.getMessage();  
      } 

      model.addAttribute("msg", error);
      System.out.println("用户认证状态:"+subject.isAuthenticated());

      if(subject.isAuthenticated()){
        return "redirect:home"; 
      }else{
        return "/login.jsp"; 
      }      

    }
 }

2.6 退出

由于shiro的sessionManager管理session,所以不用开发退出功能,直接使用shiro的logout拦截器即可退出。


<!-- 请求logout.do执行退出操作 -->
/logout.do= logout

2.7 无权限访问跳转到refuse.jsp

当用户无操作权限,shiro将跳转到refuse.jsp页面。
使用注解的方式赋的权限,首先看看controller里通过注解限定的权限:

 /**
     * 查询:注解query权限:只有当realm里查回的权限里有query时才可访问该方法
     * 
     * 即访问该方法时,会先拿query权限去realm里查看授权时查回的权限里是否有query权限
     * 有的话则允许访问,否则不允许
     * @return
     * @author Peter
     */
    @RequestMapping(value = "query")
    @RequiresPermissions("query")//指定访问的权限
    public String query(){
        System.out.println("查询内容");
        return "/home.jsp";
    }

当没有权限访问时,就会跳转到refuse.jsp页面,但是注解方式配置无权限跳转需要在springMVC的配置文件(springMVC-servlet.xml)里配,可能是因为shiro注解赋权限的配置在这里面吧。代码如下:

<!-- 使用shiro注解赋权限 -->
<bean class=" org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">  
    <property name="securityManager" ref="securityManager"/>  
</bean> 

<!-- 捕获到没有权限异常跳转 到拒绝访问页-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <!-- 如果配置了视图解析,则可不用写jsp这个后缀 -->
            <prop key="org.apache.shiro.authz.UnauthorizedException">/refuse</prop>
        </props>
    </property>
</bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值