結合《spring項目框架的搭建(1):基本搭建》代碼,在此基礎上完成shiro的整合。java
整合前的準備web
<!--shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</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.version>1.4.0</shiro.version> 表示shiro使用的版本號,這裏使用的當前時間的最新版本。spring
新建一個ShiroDbRealm.java類繼承AuthorizingRealm,複寫父類中的兩個方法apache
doGetAuthorizationInfo,AuthenticationInfo;使用 @Component註解將對象交給容器管理。api
僞代碼以下:緩存
/** * 受權查詢回調函數, 進行鑑權但緩存中無用戶的受權信息時調用. */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //獲取當前登陸的用戶名,等價於(String)principals.fromRealm(this.getName()).iterator().next() String currentUsername = (String)super.getAvailablePrincipal(principals); Admin admin=adminService.findByUserName(currentUsername); List<String> roles = new ArrayList<String>();//存放該用戶具有的角色 List<String> permissions = new ArrayList<String>();//存放該用戶具有的權限 //查詢用戶擁有的角色和對應的權限 List<AdminRole> adminRolesList=adminRolesService.findByAdminId(admin.getId()); if(adminRolesList!=null && adminRolesList.size()>0){ Role role; for (AdminRole adminRoles:adminRolesList){ role=roleService.get(Role.class,adminRoles.getRoleId()); roles.add(role.getRoleName()); RolePermission permission=roleService.findRolePermission(role.getId()); if (permission!=null){ permissions.addAll(permission.getPermissionList()); } } } //用來保存認證好的信息, SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); if (admin.getIdentity()==1){ info.addRole("admin"); info.addStringPermission("*:*"); }else { info.addRoles(roles); info.addStringPermissions(permissions); } return info; } /** * 認證回調函數,登陸時調用. */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken; Admin admin=adminService.findByUserName(token.getUsername()); if (admin!=null){ return new SimpleAuthenticationInfo(admin.getUsername(),admin.getPassword(),admin.getRealName()); }else { return null; } }
AuthenticationInfo登陸成後會執行此方法,可是須要在登陸成功後的位置顯示調用subject.login(token).安全
身份認證成功後會進入doGetAuthorizationInfo進行權限認證和存儲。session
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"> <description>Shiro安全配置</description> <!-- Shiro 安全管理器--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroDbRealm"/> </bean> <!-- Shiro 過濾器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!--shiro 核心權限管理器 必須配置--> <property name="securityManager" ref="securityManager"/> <!--身份認證失敗跳轉的登陸頁面--> <property name="loginUrl" value="/admin/login"/> <!--認證成功跳轉的指定頁面--> <property name="successUrl" value="/admin/index"/> <!--權限認證失敗跳轉的指定頁面--> <property name="unauthorizedUrl" value="/admin/unautho"/> <!--url 過濾規則--> <property name="filterChainDefinitions"> <value> /admin/login = anon /admin/doLogin = anon /admin/logout = authc /admin/unautho=anon <!--/admin/** = [*:*]--> </value> </property> </bean> <!-- 保證明現了Shiro內部lifecycle函數的bean執行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 開啓Shiro註解 AOP式方法級權限檢查 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> </beans>
同時在spring.xml中添加 <import resource="spring-shiro.xml"/>app
<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>/admin/*</url-pattern> </filter-mapping>
@RequestMapping(value = "doLogin",method = RequestMethod.POST) public ApiBean doLogin(String username, String password, Boolean rememberMe, HttpSession session, HttpServletRequest request){ ApiBean apiBean; if (StrKit.notNull(username,password)) { //驗證用戶名密碼是否正確 JSONObject loginRes=adminService.login(username,password); if (loginRes.getBoolean("login")){ Admin admin= (Admin) loginRes.get("admin"); UsernamePasswordToken token = new UsernamePasswordToken(admin.getUsername(),admin.getPassword()); Subject subject = SecurityUtils.getSubject(); subject.login(token); apiBean= ApiBean.responseSuccess("登陸成功"); } else { apiBean= ApiBean.responseError(loginRes.getString("msg")); } } else { apiBean= ApiBean.responseError("用戶名密碼錯誤"); } return apiBean; }
當subject.login(token)以後,會進入到自定義的realm中的AuthenticationInfo方法,該方法執行完成後會執行doGetAuthorizationInfo方法。在這裏我顯示的調用了service裏的方法去驗證用戶名密碼是否正確,在正確以後再將用戶交由shiro進行二次身份覈實和權限認證。框架