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 的过滤器上,配置权限控制的拦截规则:
注意:规则是有顺序的,从上到下,拦截范围必须是从小到大的
/login = anon
/logout = logout
/admin/userlist = roles[user]
/admin/addUser = roles[admin]
/admin/** = authc
/**= anon
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 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
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}
3、登录访问项目
页面简单做了跳转:
有无访问权限在 t_user_role 表添加记录
end ~