在BOS项目中应用shiro框架进行认证

在BOS项目中应用shiro框架进行认证

概念:

认证:系统提供的用于识别用户身份的功能,通常登录功能就是认证功能-----让系统知道你是谁??

授权:系统授予用户可以访问哪些功能的许可(证书)----让系统知道你能做什么??

 

常见的权限控制方式

URL拦截权限控制(此文章使用这个)

底层基于拦截器或者过滤器实现

 

方法注解权限控制

https://blog.csdn.net/qq_36138324/article/details/80087191

底层基于代理技术实现,为Action创建代理对象,由代理对象进行权限校验

shiro官网:shiro.apache.org

shiro框架的核心功能:

认证、授权、会话管理、加密

 

shiro框架认证流程

Application Code:应用程序代码,由开发人员负责开发的

Subject:框架提供的接口,代表当前用户对象

SecurityManager:框架提供的接口,代表安全管理器对象

Realm:可以开发人员编写,框架也提供一些,类似于DAO,用于访问权限数据



begin!

第一步:引入shiro框架相关的jar

		 <!-- 引入shiro框架的依赖 -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-all</artifactId>
			<!-- <version>1.2.2</version> -->
			<version>1.3.2</version>
		</dependency>

第二步:在web.xml中配置spring框架提供的用于整合shiro框架的过滤器

  	<!-- shiro的过滤器一定要写在在struts2的过滤器之前,否则方法注解配置权限控制的方式将会失效
  	注意,过滤器的name要复制一遍,去spring的配置文件中添加一个bean name就是这个,否则引发
  	org.springframework.beans.factory.NoSuchBeanDefinitionException: 
  						No bean named '<filter-name>abc</filter-name>中间的abc' available -->
  	<filter>
  		<filter-name>shiroFilter</filter-name>
  		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  	</filter>
  	<filter-mapping>
  		<filter-name>shiroFilter</filter-name>
  		<url-pattern>/*</url-pattern>
  	</filter-mapping>

启动tomcat服务器,抛出异常:spring工厂中不存在一个名称为“shiroFilter”的bean对象

第三步:在spring配置文件中配置bean,id为shiroFilter

<!-- 配置shiro框架的过滤器工厂对象 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
	<!-- 注入安全管理器对象 -->
	<property name="securityManager" ref="securityManager"/>
	<!-- 注入相关页面访问URL -->
	<property name="loginUrl" value="/login.jsp"/>
	<property name="successUrl" value="/index.jsp"/>
	<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
	<!--注入URL拦截规则 -->
	<property name="filterChainDefinitions">
		<value>
			/css/** = anon	<!-- anon匿名访问,就是可以不用任何权限和认证就能够访问到的资源 -->
			/js/** = anon	<!-- 如若不放行的话登陆界面都进不了,因为css、js、image等等都加载不出来 -->
			/images/** = anon
			/validatecode.jsp* = anon
			/login.jsp = anon
			/UserAction_login = anon<!-- 
			下面的perms新的过滤器,检查当前登录用户是否具有staff-list,就是查看取派员的列表这个权限
			如果权限不足就跳到上面property的name为unauthorizedUrl的权限不足页面 -->
			/page_base_staff.action = perms["staff-list"]		
			/* = authc 		<!-- 其它路径要求都要认证通过才允许访问,否则跳转到property的name为loginUrl页面 -->
		</value>
	</property>
</bean>

记得一定要写上/login.jsp =anon/UserAction_login = anon

也就是说登陆相关的路径,否则谁也别想登陆进系统

下面是框架提供的过滤器:

 

第四步:配置安全管理器

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"/>

第五步:修改UserAction中的login方法,使用shiro提供的方式进行认证操作

	
	/**
	 * 用户登陆
	 * @return
	 * @throws Exception
	 */
	public String login() throws Exception {
		// 拿到存储到session的验证码
		String fwqYzm = (String) ServletActionContext.getRequest().getSession().getAttribute("key");
		if (StringUtils.isNotBlank(checkcode) && checkcode.trim().equals(fwqYzm)) {// 验证码成功
			//使用shiro框架提供的方式进行认证操作    
			Subject subject =  SecurityUtils.getSubject();
			// 获得model中已经封装好的账号密码
			String username = super.model.getUsername();
			String password = super.model.getPassword();
			password = MD5Utils.md5(password);				//记得加密验证,因为数据库存储的不是明文
			// 创建用户名密码令牌对象
			AuthenticationToken token = new UsernamePasswordToken(username,password);
			// 由于这个方法方法没有返回值,所以需要用try,catch的方式来包裹验证的方法
            try {
            	subject.login(token);					// 执行登陆
            	/*
            	 * 这个Subject在认证的时候会调用安全管理器对象(Shiro SecurityManager)进行认证
            	 * 但由于安全管理器需要用到Realm,所以需要自己创建一个class实现Realm这个接口
            	 * 不过一般为了简便省事,所以一般直接继承Realm的子类AuthorizingRealm
            	 * 这个项目的Realm创建在/Logistics_bos-service/src/main/java/shun/bos/realm/BOSRealm.java
            	 */
            } catch (UnknownAccountException e ) {
    			this.addActionError("用户未注册");
    			return LOGIN;// 返回的常量就是小写的"login"
            } catch (IncorrectCredentialsException e ) {
    			this.addActionError("密码错误!!");
    			return LOGIN;// 返回的常量就是小写的"login"
            } catch (LockedAccountException e ) {
    			this.addActionError("该账户不可用~");
    			return LOGIN;// 返回的常量就是小写的"login"
            } catch (ExcessiveAttemptsException e ) {
    			this.addActionError("尝试次数超限!!");
    			return LOGIN;// 返回的常量就是小写的"login"
            }
            /**
             * 通过subject取出user对象,在Realm类里我写了这么一句
             * AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
             * 所以取的出来
             */
            BcUser user = (BcUser) subject.getPrincipal();
            // 将user对象存入session域
			ServletActionContext.getRequest().getSession().setAttribute("user", user);
			return "index";								// shiro框架没有抛出异常说明认证成功
		}else {// 验证码失败跳回登录界面 
			this.addActionError("验证码错误!");
			return LOGIN;// 返回的常量就是小写的"login"
		}
	}
	
	/**
	 * 用户登陆,在没有用shiro框架之前用的方法,作为备份,以防修改出错
	 * @return
	 * @throws Exception
	 */
	public String login_old() throws Exception {
		// 拿到存储到session的验证码
		String fwqYzm = (String) ServletActionContext.getRequest().getSession().getAttribute("key");
		if (StringUtils.isNotBlank(checkcode) && checkcode.trim().equals(fwqYzm)) {// 验证码成功
			// 由于账号密码已经封装到了model里面了,所以直接传递到service层去校验
			boolean result = userService.check(this.model);
			if (result) {
				return "index";
			}else {
				this.addActionError("账号或密码错误!");
				return LOGIN;
			}
		}else {// 验证码失败跳回登录界面 
			this.addActionError("验证码错误!");
			return LOGIN;// 返回的常量就是小写的"login"
		}
	}
	

第六步:自定义realm,并注入给安全管理器

package shun.bos.realm;

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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import shun.bos.dao.IUserDao;
import shun.bos.domain.BcUser;

/**
* @author czs
* @version 创建时间:2018年4月25日 上午11:24:00 
*  这个Shiro框架的Subject在认证的时候会调用安全管理器对象(Shiro SecurityManager)进行认证
*  但由于安全管理器需要用到Realm,所以需要自己创建一个class实现Realm这个接口
*  不过一般为了简便省事,所以一般直接继承Realm的子类AuthorizingRealm
*/
public class BOSRealm extends AuthorizingRealm {
	
	@Autowired
	private IUserDao userDao;

	@Override
	/**
	 * 授权方法
	 */
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		// TODO 自动生成的方法存根
		return null;
	}

	@Override
	/**
	 * 认证方法
	 */
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
		System.out.println("自定义的Realm中的认证方法执行了");
		UsernamePasswordToken passwordToken = (UsernamePasswordToken) arg0;
		// 获得页面输入的用户名和密码
		String username = passwordToken.getUsername();
		// 根据用户名查询数据库,返回一个user对象,这个对象里面当然就包含了密码
		BcUser user = userDao.findUserByUsername(username);
		if (user == null) {
			return null;			// 页面输入的用户名不存在,调用方出现异常,认证失败
		}
		/**
		 *简单认证信息对象 SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) 
		 *这三个参数分别要传入user对象,因为在调用subject.login(token)方法没有异常之后
		 *将会通过BcUser user = (BcUser) subject.getPrincipal();来取出user对象
		 *要将user对象存入session域、第二个是对象的密码、最后一个String realmName就传入this.getName()就好 
		 */
		AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
		// 由框架负责比对数据库中的密码和页面输入的密码是否一致
		return info;
	}
}

 

最后修改bean为securityManager的安全管理器,将自定义的realm注入给安全管理器

	<!-- 安全管理器对象 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><!-- 
		这个Shiro框架的Subject在认证的时候会调用安全管理器对象(Shiro SecurityManager)进行认证,也就是当前bean
		但由于安全管理器需要用到Realm,所以需要自己创建一个class实现Realm这个接口,这个realm引用下面的bean -->
		<property name="realm" ref="bosRealm"/>
	</bean>
	
	<!-- 注册realm -->
	<bean name="bosRealm" class="shun.bos.realm.BOSRealm"/>


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值