Shiro 基于角色授权的简单应用与权限过滤器配置含义

一、Shiro 支持有三种方式的授权:

1、编程式:通过写 if/else 授权代码完成(不常用)

2、注解和配置式:通过执行 Java 方法上的放置的相应注释或xml 配置完成,没有权限将抛出相应异常。(中小项目注解更常用,配置+数据库更灵活)

3、jsp标签式:在 jsp 页面通过相应标签完成。(主要用于对当前用户没权限访问的内容,可以通过jsp标签隐藏掉)

 

二、Shiro 权限过滤器具体配置的含义:

anon:例如 /admins/**=anon 表示可以匿名使用,没有参数

authc:例如 /admins/user/**=authc 表示需要认证(登录)才能使用,没有参数

user:例如 /admins/user/**=user 没有参数,表示必须存在用户,当登入操作时不做检查

roles[角色]:例如 /admins/user/**=roles[admin] 参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如 /admins/user/**=roles["admin,guest"],登录用户同时具有后面的所有角色才能通过认证,相当于hasAllRoles()方法。

perms[权限]:例如 /admins/user/**=perms[user:add:*] 参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,                               例如 /admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

 

rest:rest 风格拦截器,自动根据请求方法构建权限字符串。 /admins/user/**=rest[user] 根据请求的方法,相当于 /admins/user/**=perms[user:method] 其中method为post,get,delete等。

port:例如 /admins/user/**=port[8081] 当请求的url的端口不是8081是跳转到 schemal://serverName:8081?queryString 其中:

           schmal 是协议http或https等,   

           serverName 是你访问的host,8081是url配置里port的端口,

           queryString 是你访问的url里的?后面的参数。

authcBasic:例如 /admins/user/**=authcBasic 没有参数,表示httpBasic认证

ssl:例如 /admins/user/**=ssl 没有参数,表示安全的url请求,协议为https         

logout:例如 /logout=logout 退出拦截器,退出登录         

         

注意:user 和 authc 不同:

        当应用开启了rememberMe时,用户下次访问时可以是一个user,但绝不会是authc,因为authc是需要重新认证。

说白了,以前的一个用户登录时开启了rememberMe,然后他关闭浏览器,下次再访问时他就是一个user,而不会authc。

 

三、基于角色授权的简单应用

数据表:

    

1、spring.xml 在配置 shiro 的过滤器上,配置权限控制的拦截规则:

        注意:规则是有顺序的,从上到下,拦截范围必须是从小到大的

    <!-- 配置shiro的一些拦截规则,id必须和web.xml中的 shiro 拦截器名一致 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    	<!-- Shiro的核心安全接口,这个属性是必须的 -->  
		<property name="securityManager" ref="securityManager" />
		<!-- 身份认证失败,则跳转到登录页面的配置 --> 
		<property name="loginUrl" value="/login" />  
		<!-- 登录成功后的页面 -->
		<property name="successUrl" value="/admin/index" />  
		<!-- 权限认证失败,则跳转到指定页面 --> 
		<property name="unauthorizedUrl"  value="/unauthorized" />  <!-- 登录后访问没有权限的页面后跳转的页面 -->
		<!-- Shiro连接约束配置,即过滤链的定义 -->  
		<property name="filterChainDefinitions">
			<value>
				<!-- 注意:规则是有顺序的,从上到下,拦截范围必须是从小到大的 -->
				<!--  url = 拦截规则(anon为匿名,authc为要登录后,才能访问,logout登出过滤) -->
				/login = anon
				/logout = logout
				/admin/userlist = roles[user]
				/admin/addUser = roles[admin]
				/admin/** = authc    
				/**= anon  
			</value>
		</property>
	</bean>

2、自定义 ShiroRealm类的继承 AuthorizingRealm 类:

   前面其继承的是 AuthenticatingRealm类:只作登录认证,继承它就可以。

   现在既要做登录认证,又要做授权认证,就要使用AuthenticatingRealm的子类:AuthorizingRealm

   AuthorizingRealm类的特点

    继承了父类AuthenticatingRealm但并没有去实现父类中处理登录认证的 doGetAuthenticationInfo()抽象方法,同时又多出了一个用来进行授权认证的 doGetAuthorizationInfo()抽象方法。

   这两个方法都需要在自定义 ShiroRealm 类中去实现。

   

import java.util.Set;

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.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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import cn.jq.ssm.dao.RoleMapper;
import cn.jq.ssm.dao.UserMapper;
import cn.jq.ssm.model.User;

public class ShiroRealm extends AuthorizingRealm{
	@Autowired
	private UserMapper userMapper;
	@Autowired
	private RoleMapper RoleMapper;

	/**
	 *  在 shiro 中专门做登录验证的方法
	 * @param token
	 * @return
	 * @throws AuthenticationException
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken token2 = (UsernamePasswordToken) token;
		String username = token2.getUsername();
		User user = userMapper.getUserByUsername(username);
		if(user == null) {
			throw new UnknownAccountException("用户名或密码有误!");
		}
		if(user.getStatus() == 0) {
			throw new UnknownAccountException("用户名已被禁用,请联系系统管理员!");
		}
		
		/**
		 * principals: 可以使用户名,或d登录用户的对象
		 * hashedCredentials: 从数据库中获取的密码
		 * credentialsSalt:密码加密的盐值
		 * RealmName:  类名(ShiroRealm)
		 */
		ByteSource credentialsSalt = ByteSource.Util.bytes("JQSalt");
		AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPazzword(), credentialsSalt, getName());
		return info;
	}	

	/**
	 * 在 shiro 中专门做授权认证的方法
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {		
		//1 从参数 principals 中获取当前登录成功后的用户信息
		User user = principals.oneByType(User.class);
		//2 根据第一步中的用户信息,获取角色信息(若用户信息包含角色/权限信息,直接取出,若没有,从数据库中获取)
		Set<String> roles = RoleMapper.getRolesByUserid(user.getId());
		//3 把第二步获取到的登录用户关联的角色信息注入到返回的AuthorizationInfo对象中
		AuthorizationInfo info = new SimpleAuthorizationInfo(roles);
		return info;
	}
}

注意:

        SimpleAuthenticationInfo 登录认证与 SimpleAuthorizationInfo 授权认证,只需把需要信息交给 Shrio框架即可认证。

参数:PrincipalCollection principals

    1)是登录成功后的用户信息(SimpleAuthenticationInfo的第一个参数信息密切相关),谁传来的:做登录认证 doGetAuthenticationInfo 方法传来的,

    2)由于登录认证可能是多个 realm 对象,所以可能传过来多个用户信息,这个参数本质是一个集合(可能有多个元素)

    3)参数集合里的元素顺序与 多 realm 在Spring.xml 中配置的顺序有关

    4)从参数 principals 中获取当前登录成功后的用户信息

       System.out.println(principals);

       System.out.println(principals.getPrimaryPrincipal());

       System.out.println(principals.oneByType(User.class));

       System.out.println(principals.asList());

    

 RoleMapper 方法:

	<select id="getRolesByUserid" resultType="string">
		select
			r.rolecode
		from 
			 t_user u,t_role r,t_user_role ur
		where
			u.id=ur.userid and ur.roleid=r.id 
			and u.id = #{userid}
	</select>

3、登录访问项目

    页面简单做了跳转:

          

  有无访问权限在 t_user_role 表添加记录

    

  end ~

猜你喜欢

转载自blog.csdn.net/qq_42402854/article/details/89489161
今日推荐