Apache Shiro是什麼?
Apache Shiro是一個功能強大且易于使用的Java安全架構,進行認證,授權,加密和會話管理。随着Shiro的易于了解的API,你可以快速,輕松地確定任何應用程式 - 移動應用從最小的到最大的Web和企業應用。
如何使用Apache Shiro(這裡指與Spring 內建)?
1. 首先去官方網站下載下傳相關jar包(這裡使用1.2.2版本),其中包括:
shiro-core-1.2.2.jar
shiro-spring-1.2.2.jar
shiro-web-1.2.2.jar
(還需要slf4j相關jar支援)
2.在web.xml中配置shiroFilter(注意這個filter一定要放在所有的filter之前,否則不能成功使用)

3.建立一個applicationContext-shiro.xml,對shiro進行配置,内容如下:
Java代碼
- <?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:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:util="http://www.springframework.org/schema/util"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <!-- =========================================================
- Shiro Components
- ========================================================= -->
- <!-- Shiro's main business-tier object for web-enabled applications
- (use org.apache.shiro.web.mgt.DefaultWebSecurityManager instead when there is no web environment)-->
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
- <!-- Single realm app (realm configured next, below). If you have multiple realms, use the 'realms'
- property instead. -->
- <!--這裡的sampleRealm需要我們自己實作,主要包括2個方法
- 1. 使用者登入的驗證(授權)
- 2. 使用者具有的角色和權限(認證)
- 且看下面介紹-->
- <property name="realm" ref="sampleRealm"/>
- <!-- Uncomment this next property if you want heterogenous session access or clusterable/distributable
- sessions. The default value is 'http' which uses the Servlet container's HttpSession as the underlying
- Session implementation.
- <property name="sessionMode" value="native"/> -->
- </bean>
- <!-- Post processor that automatically invokes init() and destroy() methods -->
- <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
- <!-- 自定義角色過濾器 支援多個角色可以通路同一個資源 eg:/home.jsp = authc,roleOR[admin,user] 使用者有admin或者user角色 就可以通路-->
- <bean id="roleOR" class="com.yale.app.security.OneRoleAuthorizationFilter"/>
- <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml -
- web.xml uses the DelegatingFilterProxy to access this bean. This allows us
- to wire things with more control as well utilize nice Spring things such as
- PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: -->
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
- <property name="securityManager" ref="securityManager"/>
- <property name="loginUrl" value="/page/login.jsp"/>
- <property name="successUrl" value="/page/index.jsp"/>
- <property name="unauthorizedUrl" value="/register/unauthorized"/>
- <!-- The 'filters' property is usually not necessary unless performing an override, which we
- want to do here (make authc point to a PassthruAuthenticationFilter instead of the
- default FormAuthenticationFilter: -->
- <property name="filters">
- <util:map>
- <entry key="authc">
- <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/>
- </entry>
- </util:map>
- </property>
- <property name="filterChainDefinitions">
- <value>
- /page/login.jsp = anon
- /page/register
- @Component
- public class SampleRealm extends AuthorizingRealm {
- @Autowired
- private UserOperator userOperator;
- public SampleRealm() {
- setName("SampleRealm"); //This name must match the name in the User class's getPrincipals() method
- // setCredentialsMatcher(new Sha256CredentialsMatcher());
- setCredentialsMatcher(new AllowAllCredentialsMatcher());
- }
- //認證資訊,主要針對使用者登入,(下文講述在action或者controller登入過程代碼)
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
- UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
- String password = String.valueOf(token.getPassword());
- //調用操作資料庫的方法查詢user資訊
- User user = userOperator.login( token.getUsername());
- if( user != null ) {
- if(password.equals(user.getPassword())){
- Session session= SecurityUtils.getSubject().getSession();
- session.setAttribute("username", user.getLoginName());
- return new SimpleAuthenticationInfo(user.getUserId(), user.getPassword(), getName());
- }else{
- return null;
- }
- } else {
- return null;
- }
- }
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- String userId = (String) principals.fromRealm(getName()).iterator().next();
- User user = userOperator.getById(userId);
- if( user != null ) {
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- Role role = userOperator.getByRoleId(user.getRoleId());
- info.addRole(role.getRoleName());
- // info.addStringPermissions( role.getPermissions() );//如果你添加了對權限的表,打開此注釋,添加角色具有的權限
- return info;
- } else {
- return null;
- }
- }
- }
--注意shiro配置檔案中
<bean id="roleOR" class="com.yale.app.security.OneRoleAuthorizationFilter"/>
OneRoleAuthorizationFilter:為驗證多個角色可以通路同一個資源的定義:
Java代碼
- import java.io.IOException;
- import java.util.Set;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import org.apache.shiro.subject.Subject;
- import org.apache.shiro.util.CollectionUtils;
- import org.apache.shiro.web.filter.authz.AuthorizationFilter;
- public class OneRoleAuthorizationFilter extends AuthorizationFilter{
- @SuppressWarnings({"unchecked"})
- public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
- Subject subject = getSubject(request, response);
- String[] rolesArray = (String[]) mappedValue;
- if (rolesArray == null || rolesArray.length == 0) {
- //no roles specified, so nothing to check - allow access.
- return true;
- }
- boolean flag = false;
- Set<String> roles = CollectionUtils.asSet(rolesArray);
- for (String string : roles) {
- if(subject.hasRole(string)){
- flag = true;
- }
- }
- return flag;
- }
- }
4. 在工程WebRoot/page下,建立login.jsp,index.jsp,register.jsp;
這裡主要說明index.jsp
Shiro具有自己的JSP / GSP Tag Library,使用者做權限檢查判斷等等
是以我們在index.jsp引入shiro 标簽庫
裡面用很多的标簽,這裡我們主要說明:
如果使用者具有administrator 角色我們就給他顯示這個連結
如果使用者有user:create權限 我們顯示此連結
根據我上文提到的user和role表中的資料,我們在index.jsp,做如下測試:
<shiro:hasRole name="資料管理者”>
您好管理者同志!
</shiro:hasRole>
<shiro:hasRole name="普通使用者”>
您好普通使用者!
</shiro:hasRole>
5. jsp頁面寫完後,接下來我們看UserAction(使用者登入,退出等操作):
Java代碼
- //登入
- public String login(){
- UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword());
- try {
- SecurityUtils.getSubject().login(token);
- } catch (AuthenticationException e) {
- redirectPath="/page/login.jsp";
- return "redirect";
- }
- redirectPath="/page/index.jsp";
- return "redirect";
- }
- //登出
- public String loginout(){
- SecurityUtils.getSubject().logout();
- redirectPath="/login.jsp";
- return "redirect";
- }
至此基本結束,啟動項目,就可以體驗shiro的安全控制了 嘿嘿
下面說freemarker中使用shiro标簽
這個網上一搜尋就能找到答案,已經由James Gregory把代碼上傳到GitHub,
位址:https://github.com/jagregory/shiro-freemarker-tags
下載下傳該jar包 或者源代碼檔案複制到自己工程的lib下或者package中
我是講檔案複制到自己的package中使用:
如果你使用spring MVC
請看http://www.woxplife.com/articles/473.html
如果你單獨使用Freemarker 比如使用模闆生成靜态頁
在相關的類中加入如下代碼:
Configuration cfg = new Configuration();
cfg.setDefaultEncoding(“UTF-8”);
cfg.setSharedVariable("shiro", new ShiroTags());
然後在ftl頁面中使用tag:
<@shiro.hasRole name=”admin”>Hello admin!</@shiro.hasRole>
如果是使用struts2內建的freemarker作為頁面渲染
可以寫一個類extend Struts2的FreemarkerManager:
Java代碼
- import javax.servlet.ServletContext;
- import org.apache.struts2.views.freemarker.FreemarkerManager;
- import freemarker.template.Configuration;
- import freemarker.template.TemplateException;
- public class MyFreemarkerManager extends FreemarkerManager {
- @Override
- protected Configuration createConfiguration(ServletContext servletContext) throws TemplateException {
- Configuration cfg = super.createConfiguration(servletContext);
- cfg.setSharedVariable("shiro", new ShiroTags());
- return cfg;
- }
- }
然後在struts.xml中指定struts使用我們自己擴充的 FreemarkerManager
<constant name="struts.freemarker.manager.classname"
value="com.xxx.xxx.MyFreemarkerManager" />
然後在頁面中
然後在ftl頁面中使用tag:
<@shiro.hasRole name=”admin”>Hello admin!</@shiro.hasRole>
----------------------------shiro内置過濾器研究-------------------------------------------
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 |
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裡的?後面的參數。 perms:例子/admins/user/**=perms[user:add:*],perms參數可以寫多個,多個時必須加上引号,并且參數之間用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],當有多個參數時必須每個參數都通過才通過,想當于 isPermitedAll()方法。 roles:例子/admins/user/**=roles[admin],參數可以寫多個,多個時必須加上引号,并且參數之間用逗号分割,當有多個參數時,例如/admins/user/**=roles["admin,guest"],每個參數通過才算通過,相當于hasAllRoles()方法。 anon:例子/admins/**=anon 沒有參數,表示可以匿名使用。 authc:例如/admins/user/**=authc表示需要認證才能使用,沒有參數 authcBasic:例如/admins/user/**=authcBasic沒有參數表示httpBasic認證 ssl:例子/admins/user/**=ssl沒有參數,表示安全的url請求,協定為https user:例如/admins/user/**=user沒有參數表示必須存在使用者,當登入操作時不做檢查 這些過濾器分為兩組,一組是認證過濾器,一組是授權過濾器。其中anon,authcBasic,auchc,user是第一組, perms,roles,ssl,rest,port是第二組