SpringBoot集成Shiro

现在大部分系统都使用Shiro管理认证和权限,包括功能权限和内容权限,如何进一步灵活使用Shiro,需要我们了解Shiro的工作原理。

Shiro使用Web过滤器拦截用户访问,如果用户已经登录跳转工作页面,如果没有登录跳转到登录页面,Shiro的过滤器可以通过Web.xml设置,也可以通过注解设置,SpringBoot使用注解配置Shiro过滤器。

Shiro的Filter需要注入SecurityManager对象,而SecurityManager对象需要注入我们自定义的域对象myRealm,在我们域对象myRealm对象中实现Shiro的定制化功能,我们在对象myRealm中定义如何用户认证,如何给登录用户分配权限,权限分为内容权限和功能权限,我们可以设置角色,用户对应角色,角色对应权限列表,当然这些都需要通过数据库查询。

域对象myRealm是Shiro开发我们的开发接口,Shiro会回调这个对象的方法。
跟踪一下Shiro的源代码,你会发现对象myRealm作为Shiro功能扩展,主要处理认证和权限分配,而这些操作都是系统实现者需要考虑的业务逻辑,Shiro按照约定使用这些数据。

在这里插入图片描述

集成步骤:
一、修改POM依赖
在这里插入图片描述
POM.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
    <!-- 定义公共资源版本 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <relativePath/>
    </parent>
  
  <groupId>com.test</groupId>
  <artifactId>Proj_1604F</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>Proj_1604F Maven Webapp</name>
  <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
	<!--JSP支持的依赖-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <!-- 数据源依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>jconsole</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>tools</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 数据库驱动依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-solr</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils-core</artifactId>
            <version>1.8.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <scope>true</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>compile</scope>
        </dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0-RC2</version>
		</dependency>
        <!--
        <dependency>
          <groupId>com.test</groupId>
          <artifactId>gfdev</artifactId>
                <version>2.0</version>
                <scope>system</scope>
                <systemPath>${basedir}/src/lib/gfdev-2.0.jar</systemPath>
        </dependency>
        -->
    </dependencies>
  <build>
    <finalName>EC5_Proj</finalName>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<fork>true</fork>
			</configuration>
		</plugin>
	</plugins>
  </build>
</project>

二、Shiro过滤器

package com.test.util;

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

import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;

@Configuration
public class ShiroConfiguration {

    //将自己的验证方式加入容器
    @Bean
    public HkShiroRealm myShiroRealm() {
    	HkShiroRealm myShiroRealm = new HkShiroRealm();
    	myShiroRealm.setCachingEnabled(false);
        return myShiroRealm;
    }

    //权限管理,配置主要是Realm的管理认证
    @Bean
    public org.apache.shiro.mgt.SecurityManager securityManager()
    {
    	DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    //Filter工厂,设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager)
    {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String,String> map = new HashMap<String, String>();
        //登出
        map.put("/logout","logout");
        //对所有用户认证
        map.put("/**","authc");
        //对静态资源过滤权限检查
        map.put("/easyui/**", "anon");
        map.put("/images/**", "anon");
        map.put("/login","anon");
        map.put("/js/**", "anon");
        //登录
        shiroFilterFactoryBean.setLoginUrl("/init");
        //首页
        shiroFilterFactoryBean.setSuccessUrl("/main");
        //错误页面,认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/nopriv.jsp");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    //加入注解的使用,不加入这个注解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    
    @Bean
	public HandlerExceptionResolver solver(){
		HandlerExceptionResolver handlerExceptionResolver=new ShiroExceptionResolver();
		return handlerExceptionResolver;
	}
}

三、Shrio自定义域

package com.test.util;

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.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 com.test.model.UserInfo;
import com.test.service.IOrgModel;

//实现AuthorizingRealm接口用户用户认证
public class HkShiroRealm extends AuthorizingRealm{
	//用于用户查询
	@Autowired
	private IOrgModel orgmodel;
	
	//角色权限和对应权限添加
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
	{
		//获取登录用户名
		String name= (String) principalCollection.getPrimaryPrincipal();
		//查询用户名称
		UserInfo user = null;
		try
		{
			user = orgmodel.getUserByLoginId(name);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		//判断是否为超级管理员
		if("admin".equals(user.getLoginId()))
		{
			//从数据库权限表中获取权限列表,此处使用静态配置模拟
			//simpleAuthorizationInfo.addStringPermission("/");
			simpleAuthorizationInfo.addStringPermission("url:/main");
		}
		else
		{
			//添加角色和权限
			//从数据库权限表中获取权限列表,此处使用静态配置模拟
			//simpleAuthorizationInfo.addStringPermission("/");
		}
		return simpleAuthorizationInfo;
	}
	
	//用户认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) 
			throws AuthenticationException
	{
		System.out.println("authenticationToken==="+authenticationToken);
		//在Post请求的时候会先进认证,然后在到请求
		if (authenticationToken.getPrincipal() == null) {
			return null;
		}
		//获取用户信息
		String name = authenticationToken.getPrincipal().toString();
		UserInfo user = null;
		try
		{
			user = orgmodel.getUserByLoginId(name);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		if (user == null) {
			//这里返回后会报出对应异常
			return null;
		} else {
			//这里验证authenticationToken和simpleAuthenticationInfo的信息
			SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPwd(),user.getName());
			return simpleAuthenticationInfo;
		}
	}
}

四、异常处理类

package com.test.util;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

public class ShiroExceptionResolver implements HandlerExceptionResolver{  
	  
    public ModelAndView resolveException(HttpServletRequest request,  
            HttpServletResponse response, Object handler, Exception ex)
    {
    	String url = request.getRequestURI();
        if(ex instanceof UnauthorizedException){  
            ModelAndView mv = new ModelAndView("nopriv");
            mv.addObject("url", url);
            return mv;
        }
        ex.printStackTrace();  
        ModelAndView mv = new ModelAndView("nopriv");
        mv.addObject("url", url);
        mv.addObject("exception", ex.toString().replaceAll("\n", "<br/>"));  
        return mv;
    }
}

五、Controller方法上定义注解

	@RequiresPermissions("url:/main")
	@RequestMapping("/main")
	public String main()
	{
		return "main";
	}
	

六、登录方法

	@RequestMapping("/login")
	public String login(HttpServletRequest req,HttpServletResponse resp,String loginId,String pwd)
	{
		try
		{
			System.out.println("loginId==="+loginId+",pwd==="+pwd);
			//初始化组织机构
			orgmodel.initOrgModel();
			try
			{
				String pwd2 = Util.getMD5(pwd);
		        Subject subject = SecurityUtils.getSubject();
		        UsernamePasswordToken upToken = new UsernamePasswordToken(loginId,pwd2);
		        //进行验证,这里可以捕获异常,然后返回对应信息
		        subject.login(upToken);
			}
	    	catch(UnknownAccountException uae)
	    	{
	    		req.setAttribute("showMsg", "账号错误");
	    		return "login";
	    	}
	    	catch(IncorrectCredentialsException ice)
	    	{
	    		req.setAttribute("showMsg", "密码错误");
	    		return "login";
	    	}
		
			//记录Cookie
			Cookie c = new Cookie("loginId",loginId);  
            c.setPath(req.getContextPath());
            resp.addCookie(c);
			Cookie c2 = new Cookie("pwd",pwd);  
            c2.setPath(req.getContextPath());
            resp.addCookie(c2);
			
			String pwd2 = Util.getMD5(pwd);
			Boolean rtn = orgmodel.login(loginId, pwd2);
			System.out.println("rtn="+rtn);
			return "redirect:/main";
		}
		catch(Exception e)
		{
			e.printStackTrace();
			String msg = e.getMessage();
			req.setAttribute("msg", msg);
		}
		return "redirect:/main";
	}

七、未授权页面

<%@ page language="java" contentType="text/html; charset=UTF8"
    pageEncoding="UTF8"%>
<%
	String ctx = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF8">
<title>未授权访问</title>
<link rel="stylesheet" type="text/css" href="<%=ctx%>/easyui/themes/default/easyui.css">   
<link rel="stylesheet" type="text/css" href="<%=ctx%>/easyui/themes/icon.css">   
<script type="text/javascript" src="<%=ctx%>/easyui/jquery.min.js"></script>   
<script type="text/javascript" src="<%=ctx%>/easyui/jquery.easyui.min.js"></script>
</head>
<body>
	<div id="p" class="easyui-panel" title="错误信息"     
	        style="width:500px;height:150px;padding:10px;background:#fafafa;"   
	        data-options="iconCls:'icon-tip',closable:false,    
	                collapsible:false,minimizable:false,maximizable:false">   
	    <p>未授权访问网络资源:${url}</p>   
	    <p>请联系管理员,分配授权</p>   
	</div> 
</body>
</html>

代码下载:https://pan.baidu.com/s/1MHoqF8PslpiVZVSGnbdHqg

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值