首页 > 技术文章 > shiro安全框架的使用流程

WQX-work24 2019-01-04 15:29 原文

最近学了shiro安全框架流程,在这里梳理一下shiro的工作流程和一些代码,方便以后使用的时候,能快速找到对应的代码。

 

要使用这个shiro框架,还要新建两张表 t_authority(权限表)和t_role_authority(角色权限表)

 

1.先在porm.xml中引入四个jar包,分别是shiro-core(shiro核心包)、shiro-web(shiro服务包)、shiro-spring(shiro和spring整合包)和shiro-ehcache(shiro缓存包)

<shiro.version>1.3.2</shiro.version

	 <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>
		<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>

2.在web.xml中配置filter(拦截器),拦截所有URL请求路径。

			<!-- shiro过滤器定义 -->
	<filter>
	    <filter-name>shiroFilter</filter-name>
	    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	    <init-param>
	        <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
	        <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.在application.xml(spring.xml)中配置Realm、安全管理器和shiro过滤器

 
        <!-- 配置自定义Realm -->
    <bean id="myRealm" class="com.oracle.shiro.UserRealm">
    	<property name="credentialsMatcher" >
    		<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    			<property name="hashAlgorithmName" value="MD5"></property>
    			<property name="hashIterations" value="1024"></property>
    		</bean>
    	</property>
    </bean>

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

  <!-- Shiro过滤器 核心-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全接口,这个属性是必须的 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 身份认证失败,则跳转到登录页面的配置 -->
        <property name="loginUrl" value="/login.html"/>
        <property name="successUrl" value="/index.jsp"/>
        <!-- 权限认证失败,则跳转到指定页面 -->
        <property name="unauthorizedUrl" value="/login.htmls"/>
        <!-- Shiro连接约束配置,即过滤链的定义 -->
        <property name="filterChainDefinitions">
            <value>
            	<!-- /candidate/admin/**=authc -->
                <!--anon 表示匿名访问,不需要认证以及授权-->
				/login.htmls = anon
				/css/** = anon
				/dist/** = anon
				/js/** = anon
				/user/loginIn.dodo = anon
				/user/reg.dodo = anon
				/res/** = anon
				/logout = logout
                <!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
                /**=authc
<!--            /student=roles[teacher]
                /teacher=perms["user:create"]
 -->            </value>
        </property>
    </bean>

4.新建一个UserRealm类,该类的路径对应(3)中的自定义的Realm配置的class路径。

package com.oracle.shiro;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.shiro.SecurityUtils;
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.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.util.StringUtils;

import com.oracle.model.User;
import com.oracle.service.RoleService;
import com.oracle.service.UserService;



public class UserRealm extends AuthorizingRealm {
   // 用户对应的角色信息与权限信息都保存在数据库中,通过UserService获取数据
   @Resource
     private UserService userService;

    /**
     * 提供用户信息返回权限信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    	String currentUsername = (String)super.getAvailablePrincipal(principals);
		List<String> roleList = null;  //用来存放角色码的集合
		List<String> permissionList = null;  //用来存放当前用户的权限码
		//从数据库中获取当前登录用户的详细信息
		User user = userService.findUserByUsername(currentUsername);
		if(null != user){
			permissionList = userService.getPermissions(user.getId());//根据当前登录用户的id,获取当前用户的权限码
			roleList = userService.findRolesByUserId(user.getId());//根据当前用户的id,获取当前用户的角色码
		}else{
			throw new AuthorizationException();
		}
		//为当前用户设置角色和权限
		SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
		simpleAuthorInfo.addRoles(roleList);//把用户角色码交给shiro
		simpleAuthorInfo.addStringPermissions(permissionList);//把用户权限码交给shiro
		return simpleAuthorInfo;
    }

    /**
     * 提供账户信息返回认证信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
			String username = (String) token.getPrincipal();
			User user = userService.findUserByUsername(username);
			if (user == null) {
			    // 用户名不存在抛出异常
			    throw new UnknownAccountException();
			}else{
				ByteSource salt = ByteSource.Util.bytes(user.getSalt());//盐值
				SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getName(),
						user.getPassWord(),salt,getName());
				SecurityUtils.getSubject().getSession().setAttribute("CURRENT_USER", user);
				return authenticationInfo;
			}
			
    }
    
    
    
}

 注:在(4)中从数据库中获取用户信息的方法,比较简单,就不粘贴出来了(service->dao层->mapper.xml)

5.在spring-mvc.xml中配置,开启shiro注解,shiro才能被正式使用。

 <!-- 开启Shiro注解 -->
	     <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
	 
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
    <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>  
            <prop key="org.apache.shiro.authz.UnauthorizedException">
                /unauthorized
            </prop>  
        </props>  
    </property>  
    </bean>

 

 

 

 

登录、注册的controller中的代码:

package com.oracle.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.oracle.model.User;
import com.oracle.service.UserService;

@Controller
@RequestMapping("/user")
public class UserController {
	private static Logger log = Logger.getLogger(UserController.class);
	@Autowired
	private UserService userServiceNew;
	
	@RequestMapping("/reg")
	@ResponseBody
	public Map reg(User user) {
		Map<String,Object> map = new HashMap<String,Object>();
//		user.setPassWord(JavaUtilMD5.MD5(user.getPassWord()));
		Random rd = new Random();
		int salt = rd.nextInt(100000);
		SimpleHash sh = new SimpleHash("MD5", user.getPassWord(),ByteSource.Util.bytes(salt+"") , 1024);
		user.setPassWord(sh.toString());
		user.setSalt(salt+"");
		int i = userServiceNew.save(user);
		if(i>0) {
			map.put("code", 200);
		}else {
			map.put("code", 500);
		}
		return map;
	}
	@RequestMapping("/loginIn")
	public String loginIn(User user,HttpSession session) {
		if(user == null) {//
			return "redirect:index.html?loginCode=500";
		}else {
			Subject subject = SecurityUtils.getSubject();
			// 判断当前用户是否登陆
			if (subject.isAuthenticated() == false) {
				UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassWord());
				try {
					subject.login(token);
//					Session session = subject.getSession();
				//	user = (SysUser) session.getAttribute(Constants.CURRENT_USER);
//					session.setAttribute("SESSION_USERNAME", user.getId() + "");
//					// 根据用户id查找用户角色
//					SysUser u = this.findUserByUserId(user.getId());
//					session.setAttribute("u", u);
					return "index";
				} catch (Exception e) {
					// 这里将异常打印关闭是因为如果登录失败的话会自动抛异常
					e.printStackTrace();
//					model.addAttribute("error", "用户名或密码错误");
					return "index";
				}
			} else {
//				Session session = getSession();
//				user = (SysUser) session.getAttribute(Constants.CURRENT_USER);
//				session.setAttribute("SESSION_USERNAME", user.getId() + "");
				return "index";
			}
		}
		
	}
	
	@Autowired
	HttpServletRequest request;
	@RequestMapping("/LoginInfo")
	@ResponseBody
	public Object Logininfo() {
		HttpSession httpSession=request.getSession();
		Object map=httpSession.getAttribute("CURR_USER");
		return map;		
	}
	
	@RequestMapping("/findPageData")
	@ResponseBody
	public Object findPageData(Integer page,Integer rows) {
		Integer startIndex = (page-1)*rows;
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("startIndex", startIndex);
		map.put("rows", rows);
		List<User> users = userServiceNew.findPageData(map);
		map.put("rows", users);
		map.put("total", userServiceNew.findTotleSize());
		return map;
	}
	@RequestMapping("/findAllUser")
	@ResponseBody
	public Object findAllUser() {
		return userServiceNew.findAllUser();
	}
	
	@RequestMapping("/user")
	public String user() {
		return "user";
	}
	
	@RequestMapping("/userSave")
	@ResponseBody
	public Map userSave(User user) {
		Map<String,Object> map = new HashMap<String,Object>();
		int i = userServiceNew.save(user);
		if(i>0) {
			map.put("code", 200);
		}else {
			map.put("code", 500);
		}
		return map;
	}
	
	@RequestMapping("/userUpdate")
	@ResponseBody
	public Map userUpdate(User user) {
		Map<String,Object> map = new HashMap<String,Object>();
		int i = userServiceNew.update(user);
		if(i>0) {
			map.put("code", 200);
		}else {
			map.put("code", 500);
		}
		return map;
	}
	
	@RequestMapping("/userDelete")
	@ResponseBody
	public Map userDelete(User user) {
		Map<String,Object> map = new HashMap<String,Object>();
		int i = userServiceNew.delete(user.getId());
		if(i>0) {
			map.put("code", 200);
		}else {
			map.put("code", 500);
		}
		return map;
	}
	
	@RequestMapping("/CurrUserMenu")
	@ResponseBody
	public Map<String,Object> findCurrUserMenu(){
		User user = (User)SecurityUtils.getSubject().getSession().getAttribute("CURRENT_USER");
		List<Map<String,Object>> menuList = userServiceNew.findCurrMenu(user.getId());
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("code", 100);
		map.put("msg", "");
		Map<String,Object> m = new HashMap<String,Object>();
		m.put("children", menuList);
		map.put("extend", m);
		return map;
	}
}

  

推荐阅读