apache-shiro的強大可見一斑。
(二) apache-shiro依賴的包
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-core</artifactId>
- <version>1.2.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-web</artifactId>
- <version>1.2.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-ehcache</artifactId>
- <version>1.2.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-spring</artifactId>
- <version>1.2.1</version>
- </dependency>
除此之外還有一些東西也不可少spring, spring-mvc, ibatis等
- spring.3.1.2
- spring-mvc.3.1.2
- ibatis.2.3.4
- cglib.2.2
(三) demo採取比較典型的“User-Role-Permission”模型
- -- -----------------------------------------------------
- -- Table `shiro`.`TBL_PERMISSION`
- -- -----------------------------------------------------
- DROP TABLE IF EXISTS `shiro`.`TBL_PERMISSION` ;
- CREATE TABLE IF NOT EXISTS `shiro`.`TBL_PERMISSION` (
- `PERMISSION_ID` INT NOT NULL AUTO_INCREMENT ,
- `PERMISSION_NAME` VARCHAR(45) NULL ,
- PRIMARY KEY (`PERMISSION_ID`) ,
- UNIQUE INDEX `PERMISSION_NAME_UNIQUE` (`PERMISSION_NAME` ASC) )
- ENGINE = InnoDB;
- -- -----------------------------------------------------
- -- Table `shiro`.`TBL_ROLE`
- -- -----------------------------------------------------
- DROP TABLE IF EXISTS `shiro`.`TBL_ROLE` ;
- CREATE TABLE IF NOT EXISTS `shiro`.`TBL_ROLE` (
- `ROLE_ID` INT NOT NULL AUTO_INCREMENT ,
- `ROLE_NAME` VARCHAR(45) NULL ,
- PRIMARY KEY (`ROLE_ID`) ,
- UNIQUE INDEX `ROLE_NAME_UNIQUE` (`ROLE_NAME` ASC) )
- ENGINE = InnoDB;
- -- -----------------------------------------------------
- -- Table `shiro`.`TBL_USER`
- -- -----------------------------------------------------
- DROP TABLE IF EXISTS `shiro`.`TBL_USER` ;
- CREATE TABLE IF NOT EXISTS `shiro`.`TBL_USER` (
- `USER_ID` INT NOT NULL AUTO_INCREMENT ,
- `USER_USERNAME` VARCHAR(45) NOT NULL ,
- `USER_PASSWORD` CHAR(32) NOT NULL ,
- PRIMARY KEY (`USER_ID`) ,
- UNIQUE INDEX `USER_USERNAME_UNIQUE` (`USER_USERNAME` ASC) )
- ENGINE = InnoDB;
- -- -----------------------------------------------------
- -- Table `shiro`.`TBL_PERMISSION_ROLE`
- -- -----------------------------------------------------
- DROP TABLE IF EXISTS `shiro`.`TBL_PERMISSION_ROLE` ;
- CREATE TABLE IF NOT EXISTS `shiro`.`TBL_PERMISSION_ROLE` (
- `ROLE_ID` INT NOT NULL ,
- `PERMISSION_ID` INT NOT NULL ,
- PRIMARY KEY (`ROLE_ID`, `PERMISSION_ID`) )
- ENGINE = InnoDB;
- -- -----------------------------------------------------
- -- Table `shiro`.`TBL_ROLE_USER`
- -- -----------------------------------------------------
- DROP TABLE IF EXISTS `shiro`.`TBL_ROLE_USER` ;
- CREATE TABLE IF NOT EXISTS `shiro`.`TBL_ROLE_USER` (
- `ROLE_ID` INT NOT NULL ,
- `USER_ID` INT NOT NULL ,
- PRIMARY KEY (`ROLE_ID`, `USER_ID`) )
- ENGINE = InnoDB;
自己實現一個UserDao, ibatis實現。
這個不是本文要記述的重點,簡單貼一下代碼。
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
- <sqlMap namespace="user">
- <typeAlias alias="User" type="com.ztgame.sd.domain.User"/>
- <resultMap class="User" id="result-map-01" groupBy="id">
- <result property="id" column="USER_ID" />
- <result property="username" column="USER_USERNAME" />
- <result property="password" column="USER_PASSWORD" />
- <result property="roleSet" resultMap="role.result-map-01" />
- </resultMap>
- <!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
- <sql id="select-base-01">
- SELECT
- u.USER_ID,
- u.USER_USERNAME,
- u.USER_PASSWORD,
- r.ROLE_ID,
- r.ROLE_NAME,
- p.PERMISSION_ID,
- p.PERMISSION_NAME
- FROM
- tbl_user as u,
- tbl_role as r,
- tbl_permission as p,
- tbl_permission_role as pr,
- tbl_role_user as ru
- WHERE
- u.USER_ID = ru.USER_ID
- AND
- r.ROLE_ID = ru.ROLE_ID
- AND
- p.PERMISSION_ID = pr.PERMISSION_ID
- AND
- r.ROLE_ID = pr.ROLE_ID
- </sql>
- <!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
- <select id="select-01" parameterClass="string" resultMap="result-map-01">
- <include refid="select-base-01" />
- AND
- u.USER_USERNAME = #username#
- </select>
- </sqlMap>
- public interface UserDao {
- User findUserByUsername(String username);
- }
- @Repository("userDao")
- public class UserDaoImpl implements UserDao {
- @Resource
- private SqlMapClientTemplate sqlMapClientTemplate;
- @Override
- public User findUserByUsername(String username) {
- Validate.notEmpty(username, "用戶名不可爲null或empty string");
- return (User) sqlMapClientTemplate.queryForObject("user.select-01", username);
- }
- }
(三) 用戶和權限數據源是自己設計的,應該實現自己的Realm對象。
- package com.ztgame.sd.security.realm;
- import java.util.HashSet;
- 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.UsernamePasswordToken;
- import org.apache.shiro.authz.AuthorizationInfo;
- import org.apache.shiro.authz.SimpleAuthorizationInfo;
- import org.apache.shiro.realm.AuthorizingRealm;
- import org.apache.shiro.realm.Realm;
- import org.apache.shiro.subject.PrincipalCollection;
- import org.springframework.beans.factory.InitializingBean;
- import org.springframework.util.Assert;
- import com.ztgame.sd.dao.UserDao;
- import com.ztgame.sd.domain.Permission;
- import com.ztgame.sd.domain.Role;
- import com.ztgame.sd.domain.User;
- public class JdbcRealm extends AuthorizingRealm
- implements
- Realm,
- InitializingBean
- {
- private UserDao userDao;
- // ------------------------------------------------------------------------------------------------------------
- @Override
- public void afterPropertiesSet() throws Exception {
- Assert.notNull(userDao);
- }
- // ------------------------------------------------------------------------------------------------------------
- @Override
- public String getName() {
- return getClass().getName();
- }
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- String username = (String) super.getAvailablePrincipal(principals);
- User user = userDao.findUserByUsername(username);
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- Set<String> roles = new HashSet<String>();
- Set<String> permissions = new HashSet<String>();
- for (Role role : user.getRoleSet()) {
- roles.add(role.getName());
- for (Permission per : role.getPermissionSet()) {
- permissions.add(per.getName());
- }
- }
- info.addRoles(roles);
- info.addStringPermissions(permissions);
- return info;
- }
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(
- AuthenticationToken token) throws AuthenticationException {
- SimpleAuthenticationInfo info = null;
- UsernamePasswordToken upt = (UsernamePasswordToken) token;
- String username = upt.getUsername();
- User user = userDao.findUserByUsername(username);
- if (user == null) {
- throw new AuthenticationException();
- }
- info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
- return info;
- }
- // ------------------------------------------------------------------------------------------------------------
- public void setUserDao(UserDao userDao) {
- this.userDao = userDao;
- }
- }
(四) apache-shiro的配置
web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
- <!-- apache-shiro 核心攔截器 -->
- <filter>
- <filter-name>shiroFilter</filter-name>
- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>shiroFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <!-- 其他無關apache-shiro -->
- </web-app>
spring-shiro.xml
- <?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:p="http://www.springframework.org/schema/p"
- xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util"
- xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
- <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager" />
- <property name="loginUrl" value="/login" />
- <property name="successUrl" value="/login/loginSuccessFull" />
- <property name="unauthorizedUrl" value="/login/unauthorized" />
- <!--
- <property name="filterChainDefinitions">
- <value>
- / = anon
- </value>
- </property>
- -->
- </bean>
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
- <property name="authenticator" ref="authenticator" />
- <property name="sessionManager" ref="sessionManager" />
- <property name="cacheManager" ref="cacheManager" />
- <property name="realms">
- <list>
- <bean class="com.ztgame.sd.security.realm.JdbcRealm">
- <property name="userDao" ref="userDao" />
- <property name="credentialsMatcher" ref="hashedCredentialsMatcher" />
- </bean>
- </list>
- </property>
- </bean>
- <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator" />
- <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
- <property name="sessionDAO" ref="sessionDAO" />
- </bean>
- <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager" />
- <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.MemorySessionDAO" />
- <bean id="hashedCredentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
- <property name="hashAlgorithmName" value="MD5" />
- <property name="storedCredentialsHexEncoded" value="true" />
- <property name="hashIterations" value="1" />
- </bean>
- </beans>
spring-mvc.xml
- <?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:p="http://www.springframework.org/schema/p"
- xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util"
- xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
- http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
- <!-- 其他spring-mvc框架配置 -->
- <!--
- 以下兩個bean的配置是爲了在Controller層使用元註釋控制權限
- 如果使用spring-mvc一定要不要放在webroot的配置文件中
- -->
- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" />
- <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
- <property name="securityManager" ref="securityManager" />
- </bean>
- </beans>
(五) jsp-taglib 支持
- <shiro:authenticated> 登錄之後
- <shiro:notAuthenticated> 不在登錄狀態時
- <shiro:guest> 用戶在沒有RememberMe時
- <shiro:user> 用戶在RememberMe時
- <shiro:hasAnyRoles name="abc,123" > 在有abc或者123角色時
- <shiro:hasRole name="abc"> 擁有角色abc
- <shiro:lacksRole name="abc"> 沒有角色abc
- <shiro:hasPermission name="abc"> 擁有權限abc
- <shiro:lacksPermission name="abc"> 沒有權限abc
- <shiro:principal> 顯示用戶登錄名
[官方文檔] http://shiro.apache.org/web.html#Web-taglibrary
(六) 默認過濾器(10個)
- anon -- org.apache.shiro.web.filter.authc.AnonymousFilter
- authc -- org.apache.shiro.web.filter.authc.FormAuthenticationFilter
- authcBasic -- org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
- perms -- org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
- port -- org.apache.shiro.web.filter.authz.PortFilter
- rest -- org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
- roles -- org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
- ssl -- org.apache.shiro.web.filter.authz.SslFilter
- user -- org.apache.shiro.web.filter.authc.UserFilter
- logout -- org.apache.shiro.web.filter.authc.LogoutFilter
anon:例子/admins/**=anon 沒有參數,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要認證(登錄)才能使用,沒有參數
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:例子/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
user:例如/admins/user/**=user沒有參數表示必須存在用戶,當登入操作時不做檢查
[官方文檔] http://shiro.apache.org/web.html#Web-FilterChainDefinitions
(七) 常用元註釋
- @RequiresAuthentication 驗證用戶是否登錄,等同於方法subject.isAuthenticated() 結果爲true時
- @RequiresUser 驗證用戶是否被記憶,user有兩種含義:一種是成功登錄的(subject.isAuthenticated()結果爲true)另外一種是被記憶的(subject.isRemembered()結果爲true)
- @RequiresGuest 驗證是否爲匿名請求
- @RequiresRoles 必須要有角色
- @RequiresPermissions 必須要有權限