shiro一,自定义realm

本文详细介绍了使用Shiro框架进行权限认证的过程,包括如何自定义Realm进行用户验证及权限分配,以及如何配置Spring下的Shiro拦截器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

话不多直接上代码:

@RequestMapping("/login")
	public String login(Blogger blogger,HttpServletRequest request){
		//System.out.println("BloggerController.login()......");
		Subject subject = SecurityUtils.getSubject();//获得当前登录用户
		UsernamePasswordToken token = new UsernamePasswordToken(blogger.getUserName(), CryptographyUtil.md5(blogger.getPassword(), "gcc"));
		try {
			subject.login(token);//身份认证,这时会调用自定义realm
			return "redirect:/admin/main.jsp";
		} catch (Exception e) {
			e.printStackTrace();
			request.setAttribute("blogger", blogger);//回显用户名和密码
			request.setAttribute("errorInfo", "用户名或者密码错误");
			return "login";
		}
	}

在shiro的官方API文档中,案例是以.ini文件来举例的,通过shiro的核心securityManager实例在读取配置文件的内容。如果我们希望通过数据库,并且自定义是什么表请往下看。

这里第四行代码,通过SecurityUtils类得到当前交互对象,一般就是登录的用户

第五行代码,将从页面获取的用户名和密码封装到一个token令牌中

try内的一行代码,对当前交互对象进行登录操作,执行login方法,下面就是关键,这时会执行如下代码:

/**
 * 自定义realm
 * @author gcc
 */
public class MyRealm extends AuthorizingRealm {
	
	@Resource
	private BloggerService bloggerService; 
	
	//为当前登录用户授予角色权限
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {		
		return null;
	}
	//验证当前登录用户
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		String userName=(String) token.getPrincipal();
		Blogger blogger = bloggerService.getByUserName(userName);
		if (blogger!=null) {
			SecurityUtils.getSubject().getSession().setAttribute("currentUser", blogger);//把当前用户信息放入session
			//AuthenticationInfo的第二个参数是数据库密码,内部实现会比对token的密码,如果错误,会返回报错信息, 在login()方法catch,页面提示错误
			AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(blogger.getUserName(), blogger.getPassword(), "xx");//realname可以是随意的字符串
这里我们自定义了一个realm,并且继承抽象类AuthorizingRealm,因为是抽象类,就必须实现内部存在的抽象方法,这里有两个,其中优先执行第二个。

我们来说明第二个类做了什么,首先他拿到了刚刚封装的token令牌,里面有用户名和密码,根据规范这里用来获取用户名。再之后就是自定义方法,通过用户名去自己定义的数据库和表中查询得到用户实体。到这一步心情突然好了吧,看你成功了一半了!

如果查询结果存在,则将用户信息放入session,这里可能思维敏捷的人发现了什么,我只是得到用户,但没有校验密码,怎么就能把信息放入session呢?这里记(问题一)

我们先往下看,将查询得到的用户名和密码交给授权信息这个构造方法,然后java封装的伟大就出现了,我们不用关心这个构造方法具体怎么做,我只要知道他会干什么。

这个构造方法会核对数据库得到的数据和token内的数据是否匹配,匹配就悄悄离开,否则例如密码错误,就会报错。而这个错误会通过throws往上抛出,被我们的catch抓到。这时可以在catch里做出补救措施,比如返回原先的用户名密码,提示错误,返回到登陆界面等等,也就解释了(问题一),既然会catch,放session也没事。

然后恍然大悟,哦,这个方法走完了。

之后是此类的第一个方法,用于获取角色和权限,这里暂时略过。再之后就是第一处代码中的登录成功,跳转页面,程序结束。

Stop!到这里是不是应该问,shiro怎么知道要走Myrealm!

这里环境是spring下,配置如下:

在web.xml中做以下配置:

<!-- 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>
在applicationContext配置:

<!-- 自定义Realm -->
	<bean id="myRealm" class="com.gcc.realm.MyRealm"/>  
	
	<!-- 安全管理器 -->
	<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.jsp"/> 
	    <!-- Shiro连接约束配置,即过滤链的定义 -->  
	    <property name="filterChainDefinitions">  
	        <value>
				/login=anon
				/admin/**=authc
	        </value>  
	    </property>
	</bean>  
	
	<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->  
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  
	
	<!-- 开启Shiro注解 -->
	<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>

配置我全给了哦,这里我们只关心一部分。

web的配置是对所有路径都进行shiro的过滤,就是说不管你是啥路径,都要被shiro检查校验。

app配置文件上半部分很好理解,也是我们关心的,这里我们定义了bean,给出了myrealm路径,shiro的默认web securityManager读到这个路径,然后就执行了我们的自定义realm。

再往下则是刚刚略过的角色和权限认证的配置,见代码中说明,这里单独介绍下权限的过滤,如/login路径下方法不用通过角色也权限认证就能执行,anon就是这个意思。再如/admin/*路径下需要进行角色认证,authc就是这个意思。其它关键字大伙自个查api。

一旦走权限认证就会执行之前我略过没有说明的方法,这里进行说明(代码不是一体的,我另一个demo中的)

/**
	 * 为当前登录的用户授予角色和权限
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String userName=(String)principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
		Connection con=null;
		try{
			con=dbUtil.getCon();
			authorizationInfo.setRoles(userDao.getRoles(con,userName));
			authorizationInfo.setStringPermissions(userDao.getPermissions(con,userName));
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				dbUtil.closeCon(con);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return authorizationInfo;
	}
简单易懂吧,我们通过dao方法查询得到权限和角色,然后交给授权信息实体,这里提醒一下,角色和权限的数据类型是set,取值最好有hashSet。

然后我们就可以这样用:

@RequiresPermissions("sys:sysPosition:view")
	@RequestMapping(value = {"list", ""})
	public String list(SysPosition sysPosition, HttpServletRequest request, HttpServletResponse response, Model model) {
		Page<SysPosition> page = sysPositionService.findPage(new Page<SysPosition>(request, response), sysPosition); 
		model.addAttribute("page", page);
		return "modules/sys/sysPositionList";
	}
这里关键看第一行,通过注解得到当前登录对象的权限,如果有则执行方法,没有就返回提示信息。

也可以jsp中这样用:

<div class="form-actions">
			<shiro:hasPermission name="sys:menu:edit"><input id="btnSubmit" class="btn btn-primary" type="submit" value="保 存"/> </shiro:hasPermission>
			<input id="btnCancel" class="btn" type="button" value="返 回" onclick="history.go(-1)"/>
		</div>

通过标签来让内容是否显示。

大功告成,简单的说明就到这里,内容有误的欢迎指出,谢谢了,各位同道中人!














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值