Shiro(二)——拦截器、角色和权限

Shiro(一)的代码十分简单,仅仅展示效果,在Shiro(一)的基础上,进行改进

Xml配置

配置主要看ShiroFilterFactoryBean配置,其它配置的按照需求添加,还有注解、缓存的相关配置等等

filterChainDefinitions:用于配置访问一个页面,需要经过的Filter拦截器、需要的角色和权限,语法如下:

 

  • anon:例子/admins/**=anon表示可以匿名访问
  • authc:例如/admins/user/**=authc表示需要认证才能使用,没有参数
  • perms:例子/page_base_staff.action = perms["staff"],当前用户需要有staff权限才可以访问。
  • roles:例子/admins/user/**=roles[admin],当前用户是否有这个角色权限。
  • 拦截器直接写拦截器的名称即可,如以下配置中的login拦截器

filters:可配置多个拦截器,后面介绍拦截器用法

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
        http://www.springframework.org/schema/util 
        http://www.springframework.org/schema/util/spring-util.xsd 
        http://www.springframework.org/schema/data/jpa 
        http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">

    <bean id="login" class="com.sea.shiro.LoginFilter" />

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="successUrl" value="/member/index.htm" />
        <property name="loginUrl" value="/login.htm" />
        <property name="unauthorizedUrl" value="/error.htm" />
        <property name="filterChainDefinitions">
            <value>
                /login.htm=anon
                /submit.htm=anon
                /error.htm=anon
                /member/**=login,authc,roles["member"],perms["query"]
            </value>
        </property>
        <property name="filters">
            <util:map>
                <entry key="login" value-ref="login"></entry>
            </util:map>
        </property>
    </bean>

    <!-- 授权 认证 -->
    <bean id="shiroRealm" class="com.sea.shiro.ShiroRealm" />

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

    <!-- Shiro生命周期处理器 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
</beans>

AuthorizingRealm授权领域

这个类就是Xml配置中的shiroRealm对象,主要做两件事,角色授权,账号认证,需要改写的函数如下:

doGetAuthorizationInfo:角色授权,主要就是配置用户的角色和权限两个信息,这决定了你能在此系统中做什么事;

doGetAuthenticationInfo:角色认证,简而言之,就是让服务器记住你已经登录过了。

package com.sea.shiro;

import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
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 com.sea.spring.entity.User;

/**
 * 授权领域
 * @author ChenSS on 2018年4月18日
 */
public class ShiroRealm extends AuthorizingRealm {

    /** 
     * 授权:角色分配
     */ 
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        System.out.println(user);
        //TODO: 根据User查找权限和角色
        
        SimpleAuthorizationInfo info =  new SimpleAuthorizationInfo();
        Set<String> roles = new HashSet<>();
        roles.add("member");
        info.setRoles(roles);
        Set<String> permissions = new HashSet<>();
        permissions.add("query");
        info.setStringPermissions(permissions);
        return info;  
    }

    /**
     *  认证信息,主要针对用户登录, 
     */
    @SuppressWarnings("unused")
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
            throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        System.out.println("AuthenticationInfo" + token.getUsername());
        System.out.println(token.getPassword());
        System.out.println("AuthenticationInfo" + token.getHost());
        System.out.println("AuthenticationInfo" + token.getPrincipal());
        //TODO:根据账号和密码查询用户
        User user = new User("shiro", "123456");
        if(null == user){
            throw new AccountException("帐号或密码不正确!");
        } else if(true) {
            
        } else {
            //TODO: 记录最后登录时间
        }
        return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    }
}

登录拦截器

可继承Shiro包下的AccessControlFilter类,该类的主要方法如下:

  • isAccessAllowed:表示是否允许访问;如果允许访问返回true,否则false;
  • onAccessDenied:表示当访问拒绝时是否已经处理;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。
package com.sea.shiro;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.filter.AccessControlFilter;

import com.sea.spring.entity.User;

/**
 * 
 * @author ChenSS on 2018年4月18日
 */
public class LoginFilter extends AccessControlFilter {
    final static Class<LoginFilter> CLASS = LoginFilter.class;

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception {
        System.out.println("LoginFilter ");
        User token = (User) SecurityUtils.getSubject().getPrincipal();
        System.out.println(token);
        if (null != token || isLoginRequest(request, response)) {
            return Boolean.TRUE;
        }
        if (ShiroUtils.isAjax(request)) {
            Map<String, String> resultMap = new HashMap<String, String>();
            resultMap.put("login_status", "300");
            resultMap.put("message", "当前用户没有登录");
            //因为是Ajax请求,以Json格式写回客户端,具体实现以自己代码习惯为准
            ShiroUtils.out(response, resultMap);
        }
        return Boolean.FALSE;

    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        // 保存Request和Response 到登录后的链接
        saveRequestAndRedirectToLogin(request, response);
        return Boolean.FALSE;
    }

}

登录Controller

函数同Shiro(一),主要就是在SecurityUtils.getSubject()中添加你的用户

package com.sea.spring.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.sea.spring.entity.User;

@Controller
public class LoginController {
    @RequestMapping(value = "/login")
    public ModelAndView login() {
        return new ModelAndView("/login");
    }

    @RequestMapping(value = "/submit")
    public ModelAndView submit(String username, String password) {
        User user = new User("shiro", "123456");
        try {
            // 如果登陆成功
            if (user.getName().equals(username) && user.getPassword().equals(password)) {
                UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword().toString());
                Subject subject = SecurityUtils.getSubject();
                subject.login(token);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ModelAndView("redirect:/member/index.htm");
    }
}

 

posted on 2018-04-18 22:41  疯狂的妞妞  阅读(446)  评论(0编辑  收藏  举报

导航