Shiro之SpringBoot整合-yellwcong

11 篇文章 0 订阅

Shiro来和springboot整合到一起,简单的进行shiro的授权处理操作。这个项目,简单的使用了用户的登陆和登出处理. 需要明白shiro就是一个过滤的插件,主要又Subject ,SecurityManager 以及Realm.其中Subject认证的时候,会调用SecurityManager ,然后SecurityManager (可以管理Reaml的验证策略,多个Reaml验证的策略)调用对应的 Realm做认证和授权的操作。

代码地址

这个代码库是用于演示如何通过shiro和springboot整合 ,

https://gitee.com/yellowcong/springboot-demo/tree/master/springboot-shiro

shiro的cas整合

  1. Shiro之CAS单点登录-yellowcong

  2. Spring+SpringMVC+Mybatis+Shiro框架整合-yellowcong

1. shiro的原理

Shiro在权限认证过程中,操作的是Subject的对象。 登陆的时候,实际上,是操作Realm进行用户的验证和授权操作。
在这里插入图片描述

Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;

SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;

Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

2. 代码

在这里插入图片描述

2.1 配置 Reaml

这个地方,我定义了一个简单的Reaml,需要继承AuthorizingRealm 这个类。

package com.yellowcong.realm;

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

import javax.annotation.Resource;

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 org.springframework.beans.factory.annotation.Autowired;

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

/**
 * 创建日期:2017年9月23日 <br/>
 * 创建用户:yellowcong <br/>
 * 功能描述:用于授权操作
 */
public class SampleRealm extends AuthorizingRealm {
	
	@Autowired
    private UserService userService;

    /**
     * 用户授权 
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) {
        SimpleAuthorizationInfo info =  new SimpleAuthorizationInfo();
        // 根据用户ID查询角色(role),放入到Authorization里。
        Set<String> roles = new HashSet<String>(); // 添加用户角色
        roles.add("administrator");
        info.setRoles(roles);
        // 根据用户ID查询权限(permission),放入到Authorization里。
        Set<String> permissions = new HashSet<String>(); // 添加权限
        permissions.add("/role/**");
        info.setStringPermissions(permissions);
        return info;
    }

    /**
     * 认证,用户登录
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken paramAuthenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) paramAuthenticationToken;

        User user = userService.login(token.getUsername());
        // token返回的是一个数组,将char类型转化为String类型
        String pswDate = new String(token.getPassword());
        // 当用户名 和密码都满足的情况,返回登陆信息
        if(pswDate.equals(user.getPassword())){
            return new SimpleAuthenticationInfo(token.getUsername(), token.getPassword(), getName());
        } else {
            // 当没有用户的时候,抛出异常
            throw new AuthenticationException();
        }
    }

}

2.2 配置ShiroConfig

这个就相当于spring-shiro.xml 这个配置文件了,配置了授权了接口信息。

package com.yellowcong.config;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.filter.DelegatingFilterProxy;

import com.yellowcong.realm.SampleRealm;

@Configuration
@PropertySource("classpath:shiro.properties")  // 指定读取的配置文件地址
public class ShiroConfig {
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        filterRegistration.addInitParameter("targetFilterLifecycle", "true");
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*");
        return filterRegistration;
    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean
    public SampleRealm getSampleRealm(){
    	return new SampleRealm();
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设定realm 用于权限的认证
        securityManager.setRealm(this.getSampleRealm());
        //用于securityManager 的缓存
        securityManager.setCacheManager(new MemoryConstrainedCacheManager());
        return securityManager;
    }

    /**
     * shiro的过滤器
     * @param securityManager
     * @param casFilter
     * @param casServerUrlPrefix
     * @param shiroServerUrlPrefix
     * @return
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager,
    		@Value("${shiro.loginUrl}") String loginUrl,  //登陆地址
    		@Value("${shiro.successUrl}") String successUrl, //登陆成功地址
    		@Value("${shiro.unauthorizedUrl}") String unauthorizedUrl) {  //未授权的地址 
    	ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    	
    	//设定认证管理的Manager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        
        //设定登陆地址
        shiroFilterFactoryBean.setLoginUrl(loginUrl);
        
        //设定登陆成功跳转的地址
        shiroFilterFactoryBean.setSuccessUrl(successUrl);
        //设定未授权的地址
        shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);
        
        Map<String,String> chainMap = new LinkedHashMap<>();
        chainMap.put("/user/login", "anon");        //登陆界面任何人可以访问
        chainMap.put("/error", "anon");             // erro的信息
        chainMap.put("/resources/img/**", "anon");  //图片样式可以直接访问
        chainMap.put("/resources/js/**", "anon");   //js可以直接访问
        chainMap.put("/user/list", "authc");        //用户列表需要授权
        chainMap.put("/**", "authc");   // 余下的页面,全都需要进行授权操作
        shiroFilterFactoryBean.setFilterChainDefinitionMap(chainMap);
        
        return shiroFilterFactoryBean;
    }

}  

2.3 配置文件shiro.properties

这个文件用于配置shiro登陆地址,登入成功后的跳转地址,以及未授权的地址,这些地址,是配置ShiroConfig所需要的,我们之所以单独抽取出来,是为了好配置

#shiro.properties
#没有授权的用户
shiro.cas.default.role=NO_AUTH

#登陆地址
shiro.loginUrl=/user/login

#成功地址
shiro.successUrl=/user/list

#未授权的地址
shiro.unauthorizedUrl=/user/unauthorized

2.4 用户登陆与登出处理

登陆和登出,都需要通过SecurityUtils.getSubject() 获取到Subject这个对象, 然后这个subject对象,可以直接获取到session信息,同时subject.login(token); 这个执行的时候,会调用到SecurityManager 和Reaml进行认证和授权的操作。

package com.yellowcong.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.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 创建日期:2018年5月8日<br/>
 * 代码创建:黄聪<br/>
 * 功能描述:<br/>
 */
@Controller
@RequestMapping("/user")
public class UserController {
	
	/**
	 * 用户列表
	 * @param map
	 * @return
	 */
	@RequestMapping("/list")
	public String list(ModelMap map){
		//获取subject信息
		Subject subject = SecurityUtils.getSubject();
		String username = subject.getSession(false).getAttribute("username").toString();
		
		map.put("username", username);
		return "/user/list";
	}
	
	@ResponseBody
	@RequestMapping("/unauthorized")
	public String unauthorized(){
		return "用户未授权";
	}
	
	@ResponseBody
	@RequestMapping("/page2")
	public String testPage2(){
		return "测试需要授权的页面";
	}
	
	/**
	 * 跳转到登录页面
	 * 创建日期:2017年9月23日<br/>
	 * 创建用户:yellowcong<br/>
	 * 功能描述:
	 * @return
	 */
	@RequestMapping(value="/login",method=RequestMethod.GET)
	public String loginInput(){
		return "user/loginInput";
	}
	
	/**
	 * 退出操作
	 * @return
	 */
	@RequestMapping(value="/logout")
	public String logout(){
		//登出系统
		SecurityUtils.getSubject().logout();
		return "user/loginInput";
	}

	/**
	 * 创建日期:2017年9月23日<br/>
	 * 创建用户:yellowcong<br/>
	 * 功能描述:用户登录操作
	 * @param username
	 * @param password
	 * @return
	 */
	@RequestMapping(value="/login",method=RequestMethod.POST)
	public String login(String username,String password){
		try {
			//获取subject信息
			Subject subject = SecurityUtils.getSubject();
			
			//判断用户是否授权,解决已经登陆授权的用户,重新登陆授权
			if(!subject.isAuthenticated()){
				//用户登录
				UsernamePasswordToken token = new UsernamePasswordToken(username,password);
				//保存session
				token.setRememberMe(true);
				
				subject.getSession().setAttribute("username", username);
				//登录用户
				subject.login(token);
			}
		} catch (Exception e) {
			return "/user/error";
		}
		
		return "redirect:/user/list";
	}
	
	
	@ResponseBody
	@RequestMapping("/error")
	public String error(){
		return "认证失败";
	}
}

2.5 pom.xml配置

pom.xml直接就是引用了shiro的插件。

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>ted.com</groupId>
	<artifactId>springboot-shiro</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>springboot-shiro-cas</name>
	<url>http://maven.apache.org</url>

	<!-- 引用父类依赖 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.10.RELEASE</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<fastjson.version>1.2.47</fastjson.version>
		<log4j.version>1.2.17</log4j.version>
		<java.cas.client.version>3.5.0</java.cas.client.version>
		<shiro.version>1.2.5</shiro.version>
		<ehcache.version>2.4.3</ehcache.version>
		<ganymed.version>262</ganymed.version>
		<webflow.version>2.4.4.RELEASE</webflow.version>
		<druid.version>1.1.0</druid.version>
		<mybatis.version>1.3.1</mybatis.version>


	</properties>

	<dependencies>
		<!-- 添加spring-web的依赖,直接就可以使用springmvc了 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- 导入thymeleaf模版 的依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!-- 导入邮件系统 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-mail</artifactId>
		</dependency>

		<!-- spring.thymeleaf.mode=LEGACYHTML5 -->
		<dependency>
			<groupId>net.sourceforge.nekohtml</groupId>
			<artifactId>nekohtml</artifactId>
		</dependency>

		<!-- 添加数据库驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<!-- 添加mybatis的依赖 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>${mybatis.version}</version>
		</dependency>

		<!-- 数据库连接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>${druid.version}</version>
		</dependency>

		<!-- 配置日志信息 -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.webflow</groupId>
			<artifactId>spring-binding</artifactId>
			<version>${webflow.version}</version>
		</dependency>

		<!-- 添加热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>provided</scope>
			<!--optional我没弄明白,都说必须为true,但我测试true,false,不加都可以 -->
			<optional>true</optional>
		</dependency>

		<!-- 导入hibernate验证包 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>${fastjson.version}</version>
		</dependency>

		<!--cas的客户端 -->
		<dependency>
			<groupId>org.jasig.cas.client</groupId>
			<artifactId>cas-client-core</artifactId>
			<version>${java.cas.client.version}</version>
		</dependency>

		<!-- 服务的ssh客户端 -->
		<dependency>
			<groupId>ch.ethz.ganymed</groupId>
			<artifactId>ganymed-ssh2</artifactId>
			<version>${ganymed.version}</version>
		</dependency>


		<!-- 添加Shiro权限控制 -->
		<!-- shiro 配置开始 -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-all</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<!-- 缓存 -->
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache-core</artifactId>
			<version>${ehcache.version}</version>
		</dependency>

		<!-- 调度器,用来查看session是否失效 -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-quartz</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-cas</artifactId>
			<version>${shiro.version}</version>
		</dependency>
		<!-- Shiro 配置结束 -->

	</dependencies>

	<build>
		<resources>
			<resource>
				<directory>src/main/java</directory>
				<includes>
					<include>**/*.xml</include>
				</includes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
			</resource>
		</resources>
		<plugins>
			<!-- 添加spring的插件, 就可以直接通过 mvn spring-boot:run 运行了 -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<!--在这里添加 springloader plugin,热部署 -->
				<dependencies>
					<dependency>
						<groupId>org.springframework</groupId>
						<artifactId>springloaded</artifactId>
						<version>1.2.4.RELEASE</version>
					</dependency>
				</dependencies>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狂飙的yellowcong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值