1:在pom.xml文件引入shiro的依賴java
<properties> <shiro.version>1.3.2</shiro.version> </properties> <!-- 引入shiro依賴 START--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <!-- 引入shiro依賴 END-->
2:在web.xml配置shiro的攔截器web
<!-- 配置shiro的核心攔截器 start --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <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> <!-- 配置shiro的核心攔截器 end -->
3:新建applicationContext-shiro.xml文件spring
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <!--1.配置CacheManager實例:管理Shiro相關緩存操做 --> <!-- <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"></property> </bean> --> <!--2.配置realm實例,實際的認證和受權都是由R ealm實例來完成的! --> <bean id="myRealm" class="com.mrp.shiro.MyShiroRealm"> <!-- 配置密碼匹配器 --> <property name="credentialsMatcher" ref="credentialsMatcher"/> </bean> <!--3.憑證匹配器 --> <bean id="credentialsMatcher" class="com.mrp.shiro.CustomCredentialsMatcher"> </bean> <!-- 4.配置 SecurityManager 實例. SecurityManager 是 Shiro 最核心的組件 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- <property name="cacheManager" ref="cacheManager"/> --> <property name="realm" ref="myRealm"/> </bean> <!--5.配置bean的後置處理器來自動調用Shiro中的bean的init和destroy方法。 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean> <!--6.配置使shiro註解起做用的bean,須要放在 lifecycleBeanPostProcessor後面 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"></bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"></property> </bean> <!--自定義的filter,roles[]知足其中一個角色便可--> <bean id="roleOrFilter" class="com.mrp.shiro.CustomRolesAuthorizationFilter"> </bean> <!-- 7.配置哪些頁面須要被攔截,以及訪問這些頁面所需的權限 。 該bean中的id 屬性值必須和 web.xml 文件中配置的 filter 的 filter-name 值一致 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"></property> <!-- 未認證,跳轉到哪一個頁面 --> <property name="loginUrl" value="/login.jsp"></property> <!-- 登陸成功跳轉頁面 --> <property name="successUrl" value="/biz/Login_openIndex.action"></property> <!-- 認證後,沒有權限跳轉頁面 --> <property name="unauthorizedUrl" value="/biz/SysUser_openNoPermission.action"></property> <property name="filters"> <map> <entry key="roleOrFilter" value-ref="roleOrFilter"/> </map> </property> <!-- shiro URL控制過濾器規則 anon未認證能夠訪問 authc認證後能夠訪問 perms須要特定權限才能訪問 roles須要特定角色才能訪問 user須要特定用戶才能訪問 port須要特定端口才能訪問(不經常使用) rest根據指定HTTP請求才能訪問(不經常使用) *文件夾中的所有文件 ** 文件夾中的所有文件(含子文件夾) --> <!--②配置須要被攔截的資源 以及訪問權限 --> <property name="filterChainDefinitions"> <value> <!-- anon: 表示匿名的, 即任何人均可以訪問 --> /lib/** = anon /static/** = anon /login.jsp=anon /rand/SecurityCodeImage_execute.action=anon /biz/Login_webLogin.action=anon <!--③設置訪問具體資源的權限 /biz/Login_webLogin.action=roles[admin] /user.jsp=roles[user] --> <!-- authc 表示必須通過認證以後才能夠訪問的頁面 --> <!-- /WEB-INF/page/index.jsp=authc /WEB-INF/page/welcome.jsp=authc --> <!-- perms須要特定權限才能訪問 --> /biz/SysOperateRecord_list.action=perms[sysOperateRecord] /biz/SysRight_list.action=authc,roleOrFilter["root","manager"] /**=authc </value> </property> </bean> </beans>
4:自定義Realm,新建MyShiroRealm.java數據庫
public class MyShiroRealm extends AuthorizingRealm { @Autowired private ISysUserService sysUserService; @Autowired private SysUserDAO sysUserDAO; /** * 受權 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //獲取當前登陸輸入的用戶名 String loginName = (String) principals.getPrimaryPrincipal(); //到數據庫查是否有此對象 SysUser sysUser = sysUserDAO.findSysUserByProperty("userId", loginName); if(sysUser != null) { //權限信息對象info,用來存放查出的用戶的全部的角色(role)及權限(permission) SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //查詢用戶對於的角色 List<String> userRoleList = sysUserService.findByRole(sysUser.getUserId()); //添加角色 info.addRoles(userRoleList); // 查詢用戶對應的權限(用戶->角色->權限) List<String> permissions = sysUserService.findUserPermissions(sysUser.getUserId()); //添加權限 info.addStringPermissions(permissions); return info; } return null; } /** * 登陸驗證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { //UsernamePasswordToken對象用來存放提交的登陸信息 UsernamePasswordToken token = (UsernamePasswordToken) authcToken; //查出是否有此用戶 SysUser sysUser = sysUserDAO.findSysUserByProperty("userId", token.getUsername()); if (sysUser == null) { //用戶不存在 return null;//拋出異常 } else { //用戶名存在 //參數1:用戶對象,未來要放入session,數據庫查詢出來的用戶 //參數2:憑證(密碼):密碼校驗:校驗的動做交給shiro //參數3:當前使用的Realm在Spring容器中的名字(bean的名字,自動在spring容器中尋找) SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(sysUser.getUserId(), sysUser.getPwd(), super.getName()); return authenticationInfo;//密碼校驗失敗,會自動拋出IncorrectCredentialsException } } }
5:自定義密碼匹配器(由於以前的項目都是使用spring自帶的PasswordEncoder加密與匹配,因此須要自定義密碼匹配器)apache
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher { @Override public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; //明文密碼(須要匹配的用戶輸入的那份) String rawPasswd = String.valueOf(token.getPassword()); //數據庫的中的密碼 String accountCredentials = (String) getCredentials(info); //將密碼加密與系統加密後的密碼校驗,內容一致就返回true,不一致就返回false return SystemContext.passwdDecryption(rawPasswd, accountCredentials); } }
6:自定義的filter,roles[]知足其中一個角色便可,新建CustomRolesAuthorizationFilter.java緩存
public class CustomRolesAuthorizationFilter extends AuthorizationFilter { @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { Subject subject = getSubject(request, response); String[] rolesArray = (String[]) mappedValue; if (rolesArray == null || rolesArray.length == 0) //沒有角色限制,有權限訪問 { return true; } for(int i=0;i<rolesArray.length;i++) { if(subject.hasRole(rolesArray[i]))////若當前用戶是rolesArray中的任何一個,則有權限訪問 { return true; } } return false; } }
7.修改LoginAction.java登陸的方法session
public String webLogin() { // 獲取用戶傳過來的驗證�? String passCode = (String) getRequest().getParameter("passCode"); // 獲取系統生成的驗證碼 String securityCode = (String) (getRequest().getSession().getAttribute("securityCode")); // 驗證碼校驗,不正確直接返�? if (passCode!=null&&securityCode!=null&&passCode.equals(securityCode)) { //獲取認證對象的包裝對象 Subject subject = SecurityUtils.getSubject(); //獲取頁面的用戶名跟密碼進行校驗 AuthenticationToken authenticationtoken = new UsernamePasswordToken(sysUser.getUserId(), sysUser.getPwd()); String ip = ServletActionContext.getRequest().getRemoteAddr(); //獲取用戶登陸IP sysOperateRecord.setOperateIp(ip); try{ subject.login(authenticationtoken); // 獲取用戶名,並把用戶名存入session String userName = sysUser.getUserId(); getRequest().getSession().setAttribute("userName", userName); // 把用戶對象放到session當中 sysUser = sysUserService.findByUserId(sysUser.getUserId()); ActionContext.getContext().getSession().put("sysUser", sysUser); //將用戶登陸信息放到用戶登陸記錄對象中 sysOperateRecord.setOperateContent("登陸成功"); //operateType表示日誌類型:1表示登陸,2表示其它 sysOperateRecord.setOperateType(1); sysOperateRecord.setOperateIp(ip); sysOperateRecord.setUserId(sysUser.getUserId()); sysOperateRecord.setUserName(sysUser.getFullname()); sysOperateRecord.setOperateTime(new Timestamp(System.currentTimeMillis())); //將用戶登陸記錄存放到用戶登陸記錄表中 sysOperateRecordService.add(sysOperateRecord); // System.out.println("登錄成功-------------------"); forwardView = INDEX_JSP; }catch(UnknownAccountException e){ //用戶名不存在 forwardView = LOGIN_JSP; //將用戶登陸信息放到用戶登陸記錄對象中 sysOperateRecord.setOperateContent("用戶名不存在,登陸失敗"); //operateType表示日誌類型:1表示登陸,2表示其它 sysOperateRecord.setOperateType(1); sysOperateRecord.setOperateIp(ip); sysOperateRecord.setUserId(sysUser.getUserId()); sysOperateRecord.setUserName(sysUser.getFullname()); sysOperateRecord.setOperateTime(new Timestamp(System.currentTimeMillis())); //將用戶登陸記錄存放到用戶登陸記錄表中 sysOperateRecordService.add(sysOperateRecord); }catch (IncorrectCredentialsException e) { //密碼錯誤 forwardView = LOGIN_JSP; //將用戶登陸信息放到用戶登陸記錄對象中 sysOperateRecord.setOperateContent("密碼錯誤,登陸失敗"); //operateType表示日誌類型:1表示登陸,2表示其它 sysOperateRecord.setOperateType(1); sysOperateRecord.setOperateIp(ip); sysOperateRecord.setUserId(sysUser.getUserId()); sysOperateRecord.setUserName(sysUser.getFullname()); sysOperateRecord.setOperateTime(new Timestamp(System.currentTimeMillis())); //將用戶登陸記錄存放到用戶登陸記錄表中 sysOperateRecordService.add(sysOperateRecord); }catch (AuthenticationException e) { //認證失敗 e.printStackTrace(); forwardView = LOGIN_JSP; // System.out.println("登錄失敗-------------------"); //將用戶登陸信息放到用戶登陸記錄對象中 sysOperateRecord.setOperateContent("用戶名或密碼錯誤,登陸失敗"); //operateType表示日誌類型:1表示登陸,2表示其它 sysOperateRecord.setOperateType(1); sysOperateRecord.setOperateIp(ip); sysOperateRecord.setUserId(sysUser.getUserId()); sysOperateRecord.setUserName(sysUser.getFullname()); sysOperateRecord.setOperateTime(new Timestamp(System.currentTimeMillis())); //將用戶登陸記錄存放到用戶登陸記錄表中 sysOperateRecordService.add(sysOperateRecord); } } else { // 若是驗證碼錯誤,返回用戶名和密碼,用戶不用再次輸入 inputPassword = sysUser.getPwd(); inputUserName = sysUser.getUserId(); forwardView = LOGIN_JSP; // System.out.println("驗證碼失敗-------------------"); } return SUCCESS; }
8:在主頁面使用標籤控制權限app
在頭部引入shiro標籤庫 <!-- shiro頭引入 --> <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%> <shiro:hasPermission name="userManagement"> 擁有userManagement權限的可見 </shiro:hasPermission>