在Web项目中使用shiro
1.先导入所需要的依赖包
2.【shiro-web】依赖库引用完成之后,需要修改web.xml配置文件
• 进行shiro整合一定要在web.xml配置文件中配置一个Shiro环境监听器
• 在任何一个shiro项目里面都睡存在有一个shiro.ini配置文件,需要在web.xml配置文件中为其追加一个配置的过滤器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <listener><!--shiro环境监听器--> <listener-class> org.apache.shiro.web.env.EnvironmentLoaderListener </listener-class> </listener> <filter><!--过滤shiro.ini配置文件--> <filter-name>ShiroFilter</filter-name> <filter-class> org.apache.shiro.web.servlet.ShiroFilter </filter-class> <init-param> <param-name>configPath</param-name> <param-value>classpath:shiro.ini</param-value> </init-param> </filter> <filter-mapping> <filter-name>ShiroFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> </web-app>
3.src/main/resources/目录下的shiro.ini配置文件:ini文件中主要配置有四大类:main,users,roles,urls
● main:配置shiro对象,例如securityManager,Realm,authenticator,autchStrategy等等
● users:配置静态的用户信息,包含用户名,密码,角色,一个用户可以拥有多个角色。如:lee=hello,member,dept 其中lee为用户名,hello为密码,member和dept为角色
● roles:定义角色与权限的关联。如:member=member:add,member:list,member:edit 其中代表着member角色下的add,list和edit权限
● urls:配置主要在web应用中,格式为:url=拦截器[参数],拦截器[参数],...。如:/login.jsp=anon
4.自定义Realm:
● 自定义Realm一定要实现Realm接口并覆写其中的三个方法,例如以下代码
package com.yootk.shiro.realm; import org.apache.shiro.authc.*; import org.apache.shiro.realm.Realm; public class MyselfDefaultRealm implements Realm { private static int count = 0 ; @Override public String getName() { // 获取Realm的名称 return "my-happy-realm - " + count++; } @Override public boolean supports(AuthenticationToken token) { // 判断当前的Token是否可以使用此Realm return token instanceof UsernamePasswordToken; // 当前Realm只支持“UsernamePasswordToken”类型 } @Override public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String mid = (String) token.getPrincipal() ; // 获取用户名 String password = new String((char[]) token.getCredentials()) ; // 获取密码 if (!"lee".equals(mid)) { // 此时用户名不存在 throw new UnknownAccountException("【"+mid+"】该用户信息不存在,请确认输入的用户名!") ; } if (!"hello".equals(mid)) { // 密码不正确 throw new IncorrectCredentialsException("错误的用户名或密码!") ; } return new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName()) ; } }
● 编写完自定义Ream类之后需要在shiro.ini配置文件中配置一下
[main]
#要想让自定义的Realm生效一定要配置这两项 # 将自定义的Realm定义在配置文件之中,表示此类的对象将由Shiro类负责实例化 myselfRealm=com.yootk.shiro.realm.MyselfDefaultRealm # 此时的配置就表示调用了SecurityManager子类中的setRealms()方法进行设置,内部引用使用“$”符号 securityManager.realms=$myselfRealm [urls] #web项目一定要设置过滤链,否则会报缺少FilterChainResolver /login.jsp=anon
5.配置JDBC认证信息,系统里面不仅仅只包含有自定义Realm,同时还提供有一种JdbcRealm程序,这类程序的最大特点是可以直接进行数据库的认证信息。
● 想使用JdbcRealm,首先需要修改pom.xml配置文件引入mysql-connector-java依赖包
● 修改shiro.ini配置文件,引入JdbcRealm进行程序的处理
[main] # 定义当前项目之中要使用的DataSource,此时的DataSource为MySQL驱动自带 dataSource=com.mysql.jdbc.jdbc2.optional.MysqlDataSource #dataSource.url=jdbc:mysql://localhost:3306/yootk_authentication dataSource.serverName=localhost dataSource.port=3306 dataSource.databaseName=yootk_authentication dataSource.user=root dataSource.password=mysqladmin # 定义JdbcRealm类型,为当前的使用Realm jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm # 为JdbcRealm设置要使用的数据源 jdbcRealm.dataSource=$dataSource # 设置数据库的查询操作指令 jdbcRealm.authenticationQuery=SELECT password FROM member WHERE mid=? AND locked=0 # 将当前使用的Realm整合在SecurityManager之中 securityManager.realms=$jdbcRealm [urls] /login.jsp=anon
6.Realm与Subject与token与SececurityManager与SecurityUtils的关系
● 首先创建一个SececurityManager的实例
● Realm设置数据源,读取shiro.ini文件
● SececurityManager的实例设置上具体的Realm对象
● SecurityUtils设置上SececurityManager的实例
● 通过SecurityUtils.getSubect获得Subject的对象
● 实例化对象token并向token中存入用户名和密码
● 采用subject.login(token)认证
package com.yootk.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.realm.text.IniRealm; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.junit.Test; public class TestShiroBase { public static final String USERNAME = "lee" ; // 假设此处内容为输入数据 public static final String PASSWORD = "hello" ; // 假设此处内容为输入数据 @Test public void testAuth() throws Exception { // 1、创建一个SececurityManager接口类的对象实例,使用子类为了设置realm DefaultSecurityManager securityManager = new DefaultSecurityManager() ; // 2、所有的认证信息都保存在shiro.ini文件,这个文件存储在CLASSPATH目录下; Realm realm = new IniRealm("classpath:shiro.ini") ; // 3、此时的SecurityManager需要设置上具体的realm对象信息 securityManager.setRealm(realm); // 4、如果要想进行数据的认证处理,还需要获取SecurityUtils工具类 SecurityUtils.setSecurityManager(securityManager); // 设置安全管理类实例 // 5、如果要继续用户认证处理,则首先一定要获取一个Subject(用户) Subject subject = SecurityUtils.getSubject(); // 6、利用一个专属的认证Token的结构包装输入的用户名与密码信息 AuthenticationToken token = new UsernamePasswordToken(USERNAME,PASSWORD) ; // 7、利用Subject实现最终的用户认证处理操作 subject.login(token); // 进行认证操作 System.out.println("用户名:" + subject.getPrincipal()); } }
7.以后开发的时候编写自定义Realm类的时候一般会继承AuthorizingRealm类,然后覆写其中的认证和授权方法。
● 认证方法是doGetAuthenticationInfo():参数类型.getPrincipal()是获取用户名,参数类型.getCredentials()是获取密码,返回值类型是new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName());
● 授权方法是doGetAuthorizationInfo():SimpleAuthorizationInfo authz = new SimpleAuthorizationInfo() ; // 返回的授权信息 ;authz.setRoles(map.get("allRoles"));//设置角色;authz.setStringPermissions(map.get("allActions"));//设置权限;return authz;//返回对象
package com.yootk.shiro.realm; import com.yootk.shiro.service.IMemberService; import com.yootk.shiro.service.impl.MemberServiceImpl; import com.yootk.shiro.vo.Member; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; // 实现用户认证与授权处理的操作 public class MemberRealm extends AuthorizingRealm { @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 本处的程序要进行用户认证的处理操作 System.out.println("【MemberRealm】============== 用户认证处理 =============="); String mid = (String) token.getPrincipal() ; IMemberService memberService = new MemberServiceImpl() ; // 获取业务层接口实例 Member member = memberService.get(mid) ; // 根据mid查询用户信息 if (member == null) { // 用户信息不存在 throw new UnknownAccountException(mid + "账户信息不存在!") ; } String password = new String((char[]) token.getCredentials()) ; if (!member.getPassword().equals(password)) { // 密码不同 throw new IncorrectCredentialsException("错误的用户名或密码!"); } if (member.getLocked().equals(1)) { // 用户锁定了 throw new LockedAccountException(mid + "账户已经被锁定!"); } return new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName()); } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("【MemberRealm】============== 用户授权处理 =============="); return null; } }
8.Shiro页面标签,修改welcome.jsp,采用shiro.jsp标签来进行控制
● 采用标签输出用户名:
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %><!--首先要导入此标签--> <h1>用户登录成功,欢迎“<shiro:principal/>”光临"</h1>
● 在用户登录界面上,根据用户是否登录过来进行表单是否显示的判断,采用如下标签用来判断用户的登录状态:
<shiro:authenticated> <h3>您已经登录过了!</h3> </shiro:authenticated>
<shiro:notAuthenticated>
<h3>您还未登录,显示登录表单!</h3>
</shiro:notAuthenticated>
● 进行用户授权的检测处理:
<shiro:hasPermission name="member:add"> <h3>当前用户拥有“member:add”的权限!</h3> </shiro:hasPermission>
9.路径访问策略:
● 下面这些属性对应的都是后面配置文件中的拦截器
● anon 允许匿名访问,不登录也可以访问
● authc 认证用户可以访问
● logout 注销访问
● noSessionCreation 第一次允许访问(如果没有session可以访问,如果有session可以访问)
● perms 权限检测访问
● roles 角色检测访问
● ssl ssl访问,检测http协议
● user RememberMe用户访问
例如下面的shiro.ini文件:
[main]
# 将自定义的Realm直接出现在当前的程序之中
memberRealm=com.yootk.shiro.realm.MemberRealm
# 将当前使用的Realm整合在SecurityManager之中
securityManager.realms=$memberRealm
# 当路径检测失败的时候,应该跳转到登录页面,此处设置登录页面路径
shiro.loginUrl=/login.jsp
[users]
admin=hello,member,dept
lee=hello,member
[roles]
member=member:add,member:list,member:edit
dept=dept:add,dept:list,dept:edit
[urls]
/login.jsp=anon
/pages/**=authc,roles[member],perms["member:add"]
● 如果要想使用这些进行访问处理,那么还需要进行一些良好的路径匹配,就可以使用以下通配符:
● "?":匹配任意的0个或1个的内容,例如:"/pages?"表示"/pages1","/pages2"匹配
● "*":匹配任意的0个,1个或多个内容,例如:"/pages*"表示"/pages","/pageslee"都可以匹配
● "**":匹配任意级的目录,例如:"/pages/**"表示匹配"/pages/"下的所有路径,如:/pages/**=authc
● 除了路径匹配之外,也可以进行角色或权限的匹配:
如:/pages/**=authc,roles[member],perms["member:add"]