一、 介紹:
shiro是apache提供的強大而靈活的開源安全框架,它主要用來處理身份認證,授權,企業會話管理和加密。
shiro功能:用戶驗證、用戶執行訪問權限控制、在任何環境下使用session API,如cs程序。可以使用多數據源如同時使用oracle、mysql。單點登錄(sso)支持。remember me服務。詳細介紹還請看官網的使用手冊:http://shiro.apache.org/reference.html
與spring security區別,個人覺得二者的主要區別是:
1、shiro靈活性強,易學易擴展。同時,不僅可以在web中使用,可以工作在任務環境內中。
2、acegi靈活性較差,比較難懂,同時與spring整合性好。
如果對權限要求比較高的項目,個人建議使用shiro,主要原因是可以很容易按業務需求進行擴展。
附件是對與shiro集成的jar整合及源碼。
二、shiro與spring集成
shiro默認的配置,主要是加載ini文件進行初始化工作,具體配置,還請看官網的使用手冊(http://shiro.apache.org/web.html)init文件不支持與spring的集成。此處主要是如何與spring及springmvc集成。
1、web.xml中配置shiro過濾器,web.xml中的配置類使用了spring的過濾代理類來完成。
- <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>
2、在spring中的application.xml文件中添加shiro配置:
- <!--securityManager是shiro的核心,初始化時協調各個模塊運行-->
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
- <!--單個realm使用realm,如果有多個realm,使用realms屬性代替-->
- <property name="realm" ref="leopardRealm" />
- <property name="cacheManager" ref="shiroEhcacheManager" />
- </bean>
- <!--realm配置,realm是shiro的橋梁,它主要是用來判斷subject是否可以登錄及權限等-->
- <bean id="leopardRealm" class="com.leopard.shiro.realm.LeopardRealm" />
- <!--shiro過濾器配置,bean的id值須與web中的filter-name的值相同-->
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager" />
- <!-- 沒有權限或者失敗后跳轉的頁面 -->
- <property name="loginUrl" value="/login/login.jsp" />
- <property name="successUrl" value="/main/index.jsp" />
- <property name="unauthorizedUrl" value="/login/unauthorized" />
- <property name="filterChainDefinitions">
- <value>
- /login/logoutlogout=logout
- /login/**=anon
- /**=authc,rest
- </value>
- </property>
- </bean>
- <!-- 用戶授權/認證信息Cache, 采用EhCache 緩存 -->
- <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
- <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
- </bean>
- securityManager是shiro的核心,初始化時協調各個模塊運行。
- realm是shiro的橋梁,進行數據源配置,shrio提供了常用的realm數據源配置,如LDAP的 JndiLdapRealm,JDBC的JdbcRealm,ini文件的IniRealm,properties文件的PropertiesRealm 等,也可以插入自己的 Realm實現來代表自定義的數據源。此處使用了自定義的leopardRealm進行配置,java代碼如下:
- public class LeopardRealm extends AuthorizingRealm {
- /**
- * 授權方法,在配有緩存的情況下,只加載一次。
- */
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- //獲取用戶信息的所有資料,如權限角色等.
- //info.setStringPermissions(權限集合);
- //info.setRoles(角色集合);
- return info;
- }
- /**
- * 登陸認證
- */
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
- throws AuthenticationException {
- UsernamePasswordToken usernamePasswordToke = (UsernamePasswordToken)token;
- String username = usernamePasswordToke.getUsername();
- return new SimpleAuthenticationInfo(new ShiroUser("admin", "admin"), "admin",
- ByteSource.Util.bytes("admin"), getName());
- }
- }
-
-
-
- shiroFilter:shiro的權限過濾器配置,可自定義過濾器並關聯至filterChainDefinitions中。shiro過濾器說明:
shiro過濾器對應的類:
過濾器名稱 對應的java類
authc:例如/admins/user/**=authc表示需要認證(登錄)才能使用,沒有參數。
authcBasic:例如/admins/user/**=authcBasic沒有參數表示httpBasic認證。
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里的?后面的參數。
ssl:例子/admins/user/**=ssl沒有參數,表示安全的url請求,協議為https
user:例如/admins/user/**=user沒有參數表示必須存在用戶,當登入操作時不做檢查
注:這些過濾器中anon,authcBasic,auchc,user是認證過濾器,perms,roles,ssl,rest,port是授權過濾器
- shiroFilter:shiro的權限過濾器配置,可自定義過濾器並關聯至filterChainDefinitions中。shiro過濾器說明:
-
-
login.jsp代碼
springMVC控制層代碼:
最后啟動服務登錄,實驗證明,失敗返回登錄頁,成功進入主頁。
- <%@ page language="java" pageEncoding="UTF-8"%>
- <html>
- <body>
- <form action="${pageContext.request.contextPath}/login" method="post">
- 用戶名:<input id="username" name="username" />
- 密碼:<input id="password" type="password" name="password" />
- 記住我:<input type="checkbox" name="rememberMe" />
- <input type="submit" name="submit" value="submit"/>
- </form>
- </body>
- </html>
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.IncorrectCredentialsException;
- import org.apache.shiro.authc.UnknownAccountException;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.subject.Subject;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.servlet.ModelAndView;
- @Controller("loginAction")
- @RequestMapping("/login")
- public class LoginAction {
- @RequestMapping("")
- //登錄
- public ModelAndView execute(HttpServletRequest request,
- HttpServletResponse response,String username,String password) {
- UsernamePasswordToken token = new UsernamePasswordToken(username,password);
- //記錄該令牌
- token.setRememberMe(false);
- //subject權限對象
- Subject subject = SecurityUtils.getSubject();
- try {
- subject.login(token);
- } catch (UnknownAccountException ex) {//用戶名沒有找到
- ex.printStackTrace();
- } catch (IncorrectCredentialsException ex) {//用戶名密碼不匹配
- ex.printStackTrace();
- }catch (AuthenticationException e) {//其他的登錄錯誤
- e.printStackTrace();
- }
- //驗證是否成功登錄的方法
- if (subject.isAuthenticated()) {
- return new ModelAndView("/main/index.jsp");
- }
- return new ModelAndView("/login/login.jsp");
- }
- //退出
- @RequestMapping("/logout")
- public void logout() {
- Subject subject = SecurityUtils.getSubject();
- subject.logout();
- }
- }