1. 程式人生 > >shiro身份驗證授權入門

shiro身份驗證授權入門

一、 介紹:

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類
anon org.apache.shiro.web.filter.authc.AnonymousFilter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
logout org.apache.shiro.web.filter.authc.LogoutFilter
noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter
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

anon:例子/admins/**=anon 沒有引數,表示可以匿名使用。
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是授權過濾器
至此配置工作已完成。

3、簡單登入操作:

login.jsp程式碼

<%@ 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>  

springMVC控制層程式碼:

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();  
    }  
}  

最後啟動服務登入,實驗證明,失敗返回登入頁,成功進入主頁。