本文讲述了基于springmvc+shiro实现安全管理,shiro+freemarker实现权限验证。

首先我们从web.xml开始:

  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <web-app version="2.5" xmlns
    ="http://java.sun.com/xml/ns/javaee"

  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

  5. <context-param>

  6. <param-name>contextConfigLocation</param-name>

  7. <param-value>

  8. classpath:resources/tag-context.xml

  9. classpath:resources/shiro-context.xml

  10. </param-value>

  11. </context-param>

  12. <!-- log4j -->

  13. <context-param>


  14. <param-name>log4jConfigLocation</param-name>

  15. <param-value>classpath:resources/log4j.properties</param-value>

  16. </context-param>

  17. <context-param>

  18. <param-name>log4jDelay</param-name>

  19. <param-value>10000</param-value>

  20. </context-param>

  21. <!-- Spring -->

  22. <listener>

  23. <listener-class>

  24. org.springframework.web.context.ContextLoaderListener

  25. </listener-class>

  26. </listener>

  27. <listener>

  28. <listener-class>

  29. com.itrip.rp.listener.InitConfigListener

  30. </listener-class>

  31. </listener>

  32. <!-- log4j -->

  33. <listener>

  34. <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>

  35. </listener>

  36. <!-- 日志记录过滤器 -->

  37. <filter>

  38. <filter-name>requestLogFilter</filter-name>

  39. <filter-class>

  40. com.itrip.rp.filter.RequestLogFilter

  41. </filter-class>

  42. </filter>

  43. <filter-mapping>

  44. <filter-name>requestLogFilter</filter-name>

  45. <url-pattern>/*</url-pattern>

  46. </filter-mapping>

  47. <!-- 编码过滤 -->

  48. <filter>

  49. <filter-name>encoding</filter-name>

  50. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

  51. <init-param>

  52. <param-name>encoding</param-name>

  53. <param-value>UTF-8</param-value>

  54. </init-param>

  55. </filter>

  56. <filter-mapping>

  57. <filter-name>encoding</filter-name>

  58. <url-pattern>/*</url-pattern>

  59. </filter-mapping>

  60. <!-- shiro 安全过滤器 -->

  61. <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
  62. <filter>

  63. <filter-name>shiroFilter</filter-name>

  64. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

  65. <async-supported>true</async-supported>

  66. <init-param>

  67. <param-name>targetFilterLifecycle</param-name>

  68. <param-value>true</param-value>

  69. </init-param>

  70. </filter>

  71. <filter-mapping>

  72. <filter-name>shiroFilter</filter-name>

  73. <url-pattern>/*</url-pattern>

  74. </filter-mapping>

  75. <!-- SpringMVC -->

  76. <servlet>
  77. <servlet-name>resourcePlatform</servlet-name>

  78. <servlet-class>

  79. org.springframework.web.servlet.DispatcherServlet

  80. </servlet-class>

  81. <init-param>

  82. <param-name>contextConfigLocation</param-name>

  83. <param-value>

  84. classpath:resources/applicationContext-*.xml

  85. </param-value>

  86. </init-param>
  87. <load-on-startup>1</load-on-startup>
  88. </servlet>

  89. <servlet-mapping>

  90. <servlet-name>resourcePlatform</servlet-name>

  91. <url-pattern>/*</url-pattern>

  92. </servlet-mapping>

  93. </web-app>

按照web.xml初始化顺序依次为:context-param--->listener--->filter--->servlet

tag-context.xml中主要配置了权限验证标签,代码如下:

  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <beans xmlns="http://www.springframework.org/schema/beans"

  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"

  5. default-lazy-init="true">

  6. <!--后台权限标签-->

  7. <bean id="perm" class="com.itrip.rp.core.permission.PermissionDirective"/>

  8. </beans>

权限验证标签实现类是基于freemarker标签的实现方式,具体请看源代码:

  1. package com.itrip.rp.core.permission;



  2. import java.io.IOException;

  3. import java.util.Map;



  4. import org.apache.shiro.SecurityUtils;

  5. import org.apache.shiro.subject.Subject;



  6. import com.itrip.rp.common.Constants;

  7. import com.itrip.rp.core.freemarker.DirectiveUtils;



  8. import freemarker.core.Environment;

  9. import freemarker.template.TemplateDirectiveBody;

  10. import freemarker.template.TemplateDirectiveModel;

  11. import freemarker.template.TemplateException;

  12. import freemarker.template.TemplateModel;



  13. /**

  14. * 后台管理员权限许可

  15. *

  16. * @author Benny

  17. */

  18. public class PermissionDirective implements TemplateDirectiveModel {



  19. /***

  20. * 权限验证

  21. */

  22. @SuppressWarnings("unchecked")

  23. public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {

  24. String url = DirectiveUtils.getString(Constants.PARAM_URL, params);

  25. Subject subject = SecurityUtils.getSubject();

  26. boolean pass = subject.isPermitted(url);

  27. if (pass) {

  28. body.render(env.getOut());

  29. }

  30. }

  31. }
  1. Constants.PARAM_URL="url"; //对应的值就是取freemarker标签中的url

标签形式如:

  1. <@perm url="/product/add"></@perm>
  1. Subject subject = SecurityUtils.getSubject(); //这一步是基于shiro获取认证用户对象
  1. boolean pass = subject.isPermitted(url); //这一步就是进行权限验证,权限验证通过返回true,反之返回false

这里还是非常简单的。

接下来让我们看看shiro的具体配置吧,还是先看源代码:


  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"

  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"

  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  5. http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"

  6. default-lazy-init="true">

  7. <!-- Shiro拦截器 -->

  8. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
  9. <property name="securityManager" ref="securityManager" />

  10. <property name="loginUrl" value="/login" />

  11. <property name="successUrl" value="/index" />

  12. <property name="filters">

  13. <util:map>

  14. <entry key="authc" value-ref="authcFilter" />

  15. <entry key="user" value-ref="userFilter" />

  16. <entry key="logout" value-ref="logoutFilter" />

  17. </util:map>

  18. </property>

  19. <!--authc登陆认证 user用户认证检查 logout退出 filter-->

  20. <property name="filterChainDefinitions">

  21. <value>

  22. /css/** = anon

  23. /img/** = anon

  24. /js/** = anon

  25. /favicon.ico = anon

  26. /login = authc

  27. /logout = logout

  28. /** = user

  29. </value>

  30. </property>

  31. </bean>

  32. <!-- 认证filter -->

  33. <bean id="authcFilter" class="com.itrip.rp.core.security.AdminAuthenticationFilter">
  34. <property name="adminLogin" value="/login"/>
  35. <property name="adminIndex" value="/index"/>
  36. </bean>

  37. <!-- 用户检查filter -->

  38. <bean id="userFilter" class="com.itrip.rp.core.security.AdminUserFilter"/>

  39. <!-- 退出系统filter -->

  40. <bean id="logoutFilter" class="com.itrip.rp.core.security.AdminLogoutFilter">

  41. <property name="logoutUrl" value="/login"/>

  42. </bean>

  43. <!-- 安全管理器 -->

  44. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

  45. <property name="realm" ref="authorizingRealm" />

  46. <property name="sessionManager" ref="sessionManager"/>

  47. <property name="cacheManager" ref="shiroEhcacheManager"/>

  48. </bean>

  49. <!-- 自定义登陆验证 -->

  50. <bean id="authorizingRealm" class="com.itrip.rp.core.security.AdminAuthorizingRealm">

  51. <property name="credentialsMatcher">
  52. <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">

  53. <!-- 密码加密方式 -->

  54. <property name="hashAlgorithmName" value="MD5"/>

  55. <!-- true means hex encoded, false means base64 encoded -->

  56. <property name="storedCredentialsHexEncoded" value="true"/>

  57. <!-- 迭代次数 -->

  58. <property name="hashIterations" value="1" />

  59. </bean>

  60. </property>

  61. </bean>

  62. <!-- 缓存管理 -->

  63. <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">

  64. <property name="cacheManagerConfigFile">
  65. <value>classpath:resources/ehcache-shiro.xml</value>

  66. </property>

  67. </bean>

  68. <!-- 会话Cookie 180000-->

  69. <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">


  70. <constructor-arg value="sid"/>

  71. <property name="httpOnly" value="true"/>

  72. <property name="maxAge" value="180000"/>

  73. </bean>

  74. <!-- 会话ID生成器 -->

  75. <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>

  76. <!-- 会话DAO -->

  77. <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">

  78. <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>

  79. <property name="sessionIdGenerator" ref="sessionIdGenerator"/>

  80. </bean>

  81. <!-- 会话管理器 -->

  82. <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">

  83. <property name="globalSessionTimeout" value="1800000"/>

  84. <property name="deleteInvalidSessions" value="true"/>

  85. <property name="sessionValidationSchedulerEnabled" value="true"/>

  86. <property name="sessionDAO" ref="sessionDAO"/>

  87. <property name="sessionIdCookieEnabled" value="true"/>

  88. <property name="sessionIdCookie" ref="sessionIdCookie"/>

  89. </bean>

  90. <!-- Shiro生命周期处理器-->

  91. <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

  92. </beans>

shiro缓存配置文件:ehcache-shiro.xml

  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <ehcache>

  3. <diskStore path="java.io.tmpdir/rp-shiro-ehcache"/>

  4. <defaultCache

  5. maxElementsInMemory="10000"

  6. eternal="false"

  7. timeToIdleSeconds="120"

  8. timeToLiveSeconds="120"

  9. overflowToDisk="true"

  10. diskSpoolBufferSizeMB="30"

  11. maxElementsOnDisk="10000000"

  12. diskPersistent="false"

  13. diskExpiryThreadIntervalSeconds="120"/>

  14. <cache name="shiro-activeSessionCache"

  15. maxElementsInMemory="10000"

  16. overflowToDisk="true"

  17. eternal="true"

  18. timeToLiveSeconds="0"

  19. timeToIdleSeconds="0"

  20. diskPersistent="true"

  21. diskExpiryThreadIntervalSeconds="600"/>



  22. <cache name="org.apache.shiro.realm.text.PropertiesRealm-0-accounts"

  23. maxElementsInMemory="1000"

  24. eternal="true"

  25. overflowToDisk="true"/>

  26. </ehcache>
  1. /css/** = anon
  2. /img/** = anon
  3. /js/** = anon
  4. /favicon.ico = anon

这里是对静态资源的处理,静态资源不做认证。

重要的是以下三个拦截器,分别实现了用户认证,用户检查及退出系统过程。

  1. <property name="filters">
  2. <util:map>
  3. <entry key="authc" value-ref="authcFilter" />
  4. <entry key="user" value-ref="userFilter" />
  5. <entry key="logout" value-ref="logoutFilter" />
  6. </util:map>
  7. </property>

先看看用户认证authcFilter吧:

  1. package com.itrip.rp.core.security;



  2. import java.util.Date;



  3. import javax.servlet.ServletRequest;

  4. import javax.servlet.ServletResponse;

  5. import javax.servlet.http.HttpServletRequest;

  6. import javax.servlet.http.HttpServletResponse;



  7. import org.apache.shiro.authc.AuthenticationToken;

  8. import org.apache.shiro.subject.Subject;

  9. import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

  10. import org.apache.shiro.web.util.WebUtils;

  11. import org.slf4j.Logger;

  12. import org.slf4j.LoggerFactory;



  13. import com.itrip.rp.common.Constants;

  14. import com.itrip.rp.entity.beans.UserBaseInfo;

  15. import com.itrip.rp.exception.AuthenticationException;

  16. import com.itrip.rp.exception.DisabledException;

  17. import com.itrip.rp.exception.UsernameNotFoundException;

  18. import com.itrip.rp.service.AuthenticationService;

  19. import com.itrip.rp.service.LogService;

  20. import com.itrip.rp.service.UserService;

  21. import com.itrip.rp.session.SessionProvider;

  22. import com.itrip.rp.utils.DateFormatUtils;

  23. import com.itrip.rp.utils.RequestUtils;

  24. import com.itrip.rp.utils.SpringContextUtil;



  25. /**

  26. * 自定义登陆认证filter

  27. *

  28. * @author Benny

  29. */

  30. public class AdminAuthenticationFilter extends FormAuthenticationFilter {



  31. private Logger logger = LoggerFactory.getLogger("security");



  32. /**

  33. * 执行登陆操作

  34. */

  35. @Override

  36. protected boolean executeLogin(ServletRequest request, ServletResponse response) {

  37. AuthenticationToken token = createToken(request, response);

  38. if (token == null) {

  39. String msg = "create AuthenticationToken error";

  40. throw new IllegalStateException(msg);

  41. }

  42. String username = (String) token.getPrincipal();

  43. UserBaseInfo user = userService.login(username);

  44. if (user != null) {

  45. if (!user.getStatus()) {

  46. // 用户禁用

  47. return onLoginFailure(username, token, new DisabledException(), request, response);

  48. }

  49. } else {

  50. // 用户名不存在

  51. return onLoginFailure(username, token, new UsernameNotFoundException(), request, response);

  52. }

  53. try {

  54. Subject subject = getSubject(request, response);

  55. subject.login(token);

  56. return onLoginSuccess(user, token, subject, request, response);

  57. } catch (Exception e) {

  58. // TODO Auto-generated catch block

  59. return onLoginFailure(username, token, new AuthenticationException(), request, response);

  60. }

  61. }



  62. /**

  63. * 初始化service及登陆跳转

  64. */

  65. @Override

  66. public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {

  67. if (userService == null) {

  68. userService = (UserService) SpringContextUtil.getBean(UserService.class);

  69. }

  70. if (logService == null) {

  71. logService = (LogService) SpringContextUtil.getBean(LogService.class);

  72. }

  73. if (authService == null) {

  74. authService = (AuthenticationService) SpringContextUtil.getBean(AuthenticationService.class);

  75. }

  76. if (session == null) {

  77. session = (SessionProvider) SpringContextUtil.getBean(SessionProvider.class);

  78. }

  79. boolean isAllowed = isAccessAllowed(request, response, mappedValue);

  80. // 登陆跳转

  81. if (isAllowed && isLoginRequest(request, response)) {

  82. try {

  83. issueSuccessRedirect(request, response);

  84. } catch (Exception e) {

  85. logger.error("", e);

  86. }

  87. return false;

  88. }

  89. return isAllowed || onAccessDenied(request, response, mappedValue);

  90. }



  91. @Override

  92. protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {

  93. HttpServletRequest req = (HttpServletRequest) request;

  94. HttpServletResponse res = (HttpServletResponse) response;

  95. String successUrl = getAdminIndex() != null ? getAdminIndex() : super.getSuccessUrl();

  96. WebUtils.redirectToSavedRequest(req, res, successUrl);

  97. }



  98. @Override

  99. protected boolean isLoginRequest(ServletRequest req, ServletResponse resp) {

  100. String loginUrl = getAdminLogin() != null ? getAdminLogin() : super.getLoginUrl();

  101. return pathsMatch(loginUrl, req);

  102. }



  103. /**

  104. * 登陆成功

  105. */

  106. private boolean onLoginSuccess(UserBaseInfo user, AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response)
  107. throws Exception {

  108. HttpServletRequest req = (HttpServletRequest) request;

  109. HttpServletResponse res = (HttpServletResponse) response;

  110. // 记录用户登陆信息

  111. authService.login(user, RequestUtils.getIpAddr(req), req, res, session);

  112. // 将系统当前登陆用户信息放入session

  113. session.setAttribute(req, Constants.USERNAME, user.getNickName());

  114. Date lastLogin = authService.findSecond(user.getUserId());

  115. if (lastLogin != null) {

  116. session.setAttribute(req, Constants.LAST_LOGIN_TIME, DateFormatUtils.format(lastLogin, "yyyy-MM-dd HH:mm:ss"));

  117. }

  118. logService.loginSuccess(req, user.getUserId(), "login.log.loginSuccess");
  119. return super.onLoginSuccess(token, subject, request, response);

  120. }



  121. /**

  122. * 登陆失败

  123. */

  124. private boolean onLoginFailure(String username, AuthenticationToken token, AuthenticationException e, ServletRequest request,

  125. ServletResponse response) {

  126. HttpServletRequest req = (HttpServletRequest) request;

  127. logService.loginFailure(req, "login.log.loginFailure", "userName=" + username);

  128. request.setAttribute(Constants.MESSAGE, e.getMessage());

  129. return super.onLoginFailure(token, e, request, response);

  130. }



  131. private UserService userService;

  132. private LogService logService;

  133. private SessionProvider session;

  134. private AuthenticationService authService;



  135. private String adminIndex;



  136. private String adminLogin;



  137. public String getAdminIndex() {

  138. return adminIndex;

  139. }
  140.  
  141. public void setAdminIndex(String adminIndex) {

  142. this.adminIndex = adminIndex;

  143. }



  144. public String getAdminLogin() {

  145. return adminLogin;

  146. }



  147. public void setAdminLogin(String adminLogin) {

  148. this.adminLogin = adminLogin;

  149. }

  150. }

需要说明的就是service的获取,在filter中获取spring自动注入bean需要通过spring上下文来获取,这里定义实现了获取spring上下文及注入bean的工具类SpringContextUtil.java稍后会详细说明这个类以及配置。

用户登录操作“/login”交由authcFilter处理,登录controller代码很简单:

  1. package com.itrip.rp.controller;



  2. import javax.servlet.http.HttpServletRequest;

  3. import javax.servlet.http.HttpServletResponse;



  4. import org.apache.commons.lang.StringUtils;

  5. import org.slf4j.Logger;

  6. import org.slf4j.LoggerFactory;

  7. import org.springframework.stereotype.Controller;

  8. import org.springframework.ui.ModelMap;

  9. import org.springframework.web.bind.annotation.RequestMapping;



  10. import com.itrip.rp.common.Constants;

  11. import com.itrip.rp.controller.base.BaseController;



  12. /**

  13. * 系统登陆Controller

  14. *

  15. * @author Benny

  16. *

  17. */

  18. @Controller

  19. public class LoginController extends BaseController {



  20. protected static final Logger LOG = LoggerFactory.getLogger("run");



  21. /**

  22. * 登陆

  23. *

  24. * @param request

  25. * @param response

  26. * @param model

  27. * @return

  28. */

  29. @RequestMapping(value = "/login")

  30. public String login(HttpServletRequest request, HttpServletResponse response, ModelMap model) {

  31. return "login";

  32. }



  33. /**

  34. * 系统首页

  35. *

  36. * @param message

  37. * @param request

  38. * @param response

  39. * @param model

  40. * @return

  41. */

  42. @RequestMapping(value = "/index")

  43. public String index(String message, HttpServletRequest request, HttpServletResponse response, ModelMap model) {

  44. if (!StringUtils.isBlank(message)) {

  45. model.addAttribute(Constants.MESSAGE, message);

  46. }

  47. return "product/index";

  48. }

  49. }

登录页面代码如下,username、password不要写错了:

  1. <!doctype html>

  2. <body>

  3. <form name="jvForm" action="${accessRoot}/login" method="post">

  4. <div class="loginbox round15">

  5. <dl>

  6. <dd class="fz24 pt30">User login</dd>

  7. <dd>

  8. <input type="text" placeholder="Login name" autocomplete="off" name="username">

  9. </dd>

  10. <dd>

  11. <input type="password" placeholder="Password" autocomplete="off" name="password" title="click enter login">

  12. </dd>

  13. <dd>

  14. <a href="javascript:document.jvForm.submit();" class="login-bt round3" id="btnLogin">Login</a>

  15. </dd>

  16. <font color="red" id="errTip">${message!}</font>

  17. </dl>

  18. </div>

  19. </form>

  20. </body>

  21. </html>

用户认证检查userFilter:

  1. package com.itrip.rp.core.security;



  2. import java.io.IOException;



  3. import javax.servlet.ServletRequest;

  4. import javax.servlet.ServletResponse;

  5. import javax.servlet.http.HttpServletRequest;

  6. import javax.servlet.http.HttpServletResponse;



  7. import org.apache.shiro.web.filter.authc.UserFilter;

  8. import org.apache.shiro.web.util.WebUtils;



  9. /**

  10. * 用户认证检查filter

  11. *

  12. * @author Benny

  13. */

  14. public class AdminUserFilter extends UserFilter {

  15. // 未登陆重定向到登陆页

  16. protected void redirectToLogin(ServletRequest req, ServletResponse resp) throws IOException {
  17. HttpServletRequest request = (HttpServletRequest) req;

  18. HttpServletResponse response = (HttpServletResponse) resp;

  19. WebUtils.issueRedirect(request, response, getLoginUrl());

  20. }

  21. }


最后是退出系统logoutFilter:

  1. package com.itrip.rp.core.security;



  2. import javax.servlet.ServletRequest;

  3. import javax.servlet.ServletResponse;

  4. import javax.servlet.http.HttpServletRequest;



  5. import org.apache.commons.lang.StringUtils;

  6. import org.apache.shiro.subject.Subject;

  7. import org.apache.shiro.web.filter.authc.LogoutFilter;



  8. import com.itrip.rp.common.Constants;



  9. /**

  10. * 退出系统 filter

  11. *

  12. * @author Benny

  13. */

  14. public class AdminLogoutFilter extends LogoutFilter {



  15. @Override

  16. protected String getRedirectUrl(ServletRequest req, ServletResponse resp, Subject subject) {

  17. HttpServletRequest request = (HttpServletRequest) req;

  18. String redirectUrl = request.getParameter(Constants.RETURN_URL);

  19. if (StringUtils.isBlank(redirectUrl)) {

  20. redirectUrl = getLogoutUrl();

  21. if (StringUtils.isBlank(redirectUrl)) {

  22. redirectUrl = getRedirectUrl();

  23. }

  24. }

  25. return redirectUrl;

  26. }



  27. private String logoutUrl;



  28. public void setLogoutUrl(String logoutUrl) {

  29. this.logoutUrl = logoutUrl;

  30. }



  31. public String getLogoutUrl() {

  32. return logoutUrl;

  33. }

  34. }

接下来让我们看看自定义实现的登录认证及授权Realm吧:

  1. package com.itrip.rp.core.security;



  2. import java.util.HashSet;

  3. import java.util.List;

  4. import java.util.Set;



  5. import org.apache.shiro.authc.AuthenticationException;

  6. import org.apache.shiro.authc.AuthenticationInfo;

  7. import org.apache.shiro.authc.AuthenticationToken;

  8. import org.apache.shiro.authc.SimpleAuthenticationInfo;

  9. import org.apache.shiro.authc.UsernamePasswordToken;

  10. import org.apache.shiro.authz.AuthorizationInfo;

  11. import org.apache.shiro.authz.SimpleAuthorizationInfo;

  12. import org.apache.shiro.realm.AuthorizingRealm;

  13. import org.apache.shiro.subject.PrincipalCollection;

  14. import org.apache.shiro.subject.SimplePrincipalCollection;

  15. import org.apache.shiro.util.CollectionUtils;



  16. import com.itrip.rp.entity.beans.UserBaseInfo;

  17. import com.itrip.rp.service.UserService;

  18. import com.itrip.rp.utils.SpringContextUtil;



  19. /**

  20. * 认证及授权Realm

  21. *

  22. * @author Benny

  23. */

  24. public class AdminAuthorizingRealm extends AuthorizingRealm {


  25. /**

  26. * 登陆认证

  27. */

  28. @Override
  29. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {

  30. UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

  31. if (userService == null) {

  32. userService = (UserService) SpringContextUtil.getBean(UserService.class);

  33. }

  34. UserBaseInfo user = userService.login(token.getUsername());

  35. if (user != null) {

  36. return new SimpleAuthenticationInfo(user, user.getPassword(), getName());

  37. } else {

  38. return null;

  39. }

  40. }



  41. /**

  42. * 授权

  43. */

  44. @Override

  45. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

  46. // TODO Auto-generated method stub

  47. UserBaseInfo user = (UserBaseInfo) principals.getPrimaryPrincipal();

  48. SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();

  49. if (user != null) {

  50. if (userService == null) {

  51. userService = (UserService) SpringContextUtil.getBean(UserService.class);

  52. }

  53. List<String> perms = userService.getPerms(user.getUserId());

  54. Set<String> set = new HashSet<String>(perms);

  55. if (!CollectionUtils.isEmpty(perms)) {

  56. // 权限加入AuthorizationInfo认证对象

  57. auth.setStringPermissions(set);

  58. }

  59. }

  60. return auth;

  61. }



  62. /**

  63. * 清空用户权限缓存

  64. *

  65. * @param username

  66. */

  67. public void removeUserAuthorizationInfoCache(String username) {

  68. SimplePrincipalCollection pc = new SimplePrincipalCollection();

  69. pc.add(username, super.getName());

  70. super.clearCachedAuthorizationInfo(pc);

  71. }



  72. private UserService userService;

  73. }

登录认证成功后将用户对象放入AuthenticationInfo中,以便授权过程中直接使用用户对象。

授权操作只有在第一次进行权限验证的时候才会初始化(比较重要),将用户所拥有的所有权限放入AuthorizationInfo对象。

当用户权限发生变化,就需要手动调用removeUserAuthorizationInfoCache方法去清除用户权限缓存。

最后再看看springmvc配置文件:

  1. <beans xmlns="http://www.springframework.org/schema/beans"

  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  3. xmlns:mvc="http://www.springframework.org/schema/mvc"

  4. xmlns:aop="http://www.springframework.org/schema/aop"

  5. xmlns:jdbc="http://www.springframework.org/schema/jdbc"

  6. xmlns:context="http://www.springframework.org/schema/context"

  7. xmlns:tx="http://www.springframework.org/schema/tx"

  8. xsi:schemaLocation="http://www.springframework.org/schema/beans

  9. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

  10. http://www.springframework.org/schema/context

  11. http://www.springframework.org/schema/context/spring-context-3.0.xsd

  12. http://www.springframework.org/schema/tx

  13. http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

  14. http://www.springframework.org/schema/jdbc

  15. http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd

  16. http://www.springframework.org/schema/aop

  17. http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

  18. http://www.springframework.org/schema/mvc

  19. http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
  20.  
  21. <!-- 自动依赖注入 -->

  22. <context:component-scan base-package="com.itrip.rp" />



  23. <!-- 文件上传解析器 id 必须为multipartResolver -->

  24. <bean id="multipartResolver"

  25. class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

  26. <property name="maxUploadSize" value="10485760" />

  27. </bean>



  28. <!-- 没有自定义实现拦截器的时候必须声明spring默认配置 -->

  29. <!-- <mvc:annotation-driven/> -->

  30. <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">

  31. <property name="interceptors">

  32. <list>

  33. <ref bean="adminContextInterceptor"/>
  34. </list>

  35. </property>

  36. </bean>

  37. <bean id="adminContextInterceptor" class="com.itrip.rp.interceptor.AdminContextInterceptor">

  38. <property name="excludeUrls">

  39. <list>

  40. <value>/login</value>

  41. <value>/logout</value>

  42. </list>

  43. </property>

  44. </bean>



  45. <!-- 静态资源 -->

  46. <mvc:resources location="/img/" mapping="/img/**" />

  47. <mvc:resources location="/js/" mapping="/js/**" />

  48. <mvc:resources location="/css/" mapping="/css/**" />



  49. <!-- @responsebody标签返回对象格式配置 -->

  50. <bean

  51. class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

  52. <!-- 配置信息转换,将用@responsebody注解的返回值转换为json返回前台,编码为utf-8 -->

  53. <property name="messageConverters">

  54. <list>

  55. <bean

  56. class="org.springframework.http.converter.StringHttpMessageConverter">

  57. <property name="supportedMediaTypes">

  58. <list>

  59. <value>text/html;charset=UTF-8</value
    >

  60. </list>

  61. </property>

  62. </bean>

  63. <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">

  64. <property name="supportedMediaTypes">

  65. <list>

  66. <value>application/json;charset=UTF-8</value>

  67. </list>

  68. </property>

  69. </bean>

  70. </list>

  71. </property>

  72. </bean>

  73. <!-- 异常处理 -->

  74. <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">

  75. <property name="exceptionMappings">

  76. <props>

  77. <prop key="java.lang.Exception">error/404</prop>

  78. <prop key="java.lang.Throwable">error/404</prop>

  79. </props>

  80. </property>

  81. <property name="warnLogCategory" value="WARN" />

  82. <property name="defaultErrorView" value="error/404" />

  83. </bean>



  84. <!-- 默认视图配置welcome页 -->

  85. <mvc:view-controller path="/" view-name="product/index"/>



  86. <!-- freemarker视图解析器配置 -->

  87. <bean id="freemarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">

  88. <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>

  89. <!-- 视图名后缀 -->

  90. <property name="suffix" value=".html" />

  91. <property name="contentType" value="text/html; charset=UTF-8" />

  92. <!-- request/session==true请求和会话属性都被复制到模板的属性集中,此时spring必须设置为true -->

  93. <property name="exposeRequestAttributes" value="false" />

  94. <property name="exposeSessionAttributes" value="false" />

  95. <property name="exposeSpringMacroHelpers" value="true" />

  96. </bean>

  97. <bean id="freemarkerConfig"

  98. class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">

  99. <!-- 模板路径 -->

  100. <property name="templateLoaderPath" value="/view/" />

  101. <property name="freemarkerVariables">

  102. <map>

  103. <!--后台管理权限控制 -->

  104. <entry key="perm" value-ref="perm" />

  105. </map>

  106. </property>

  107. <property name="freemarkerSettings">

  108. <props>

  109. <prop key="template_update_delay">0</prop>

  110. <prop key="defaultEncoding">UTF-8</prop>

  111. <prop key="url_escaping_charset">UTF-8</prop>

  112. <prop key="locale">zh_CN</prop>

  113. <prop key="boolean_format">true,false</prop>

  114. <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>

  115. <prop key="date_format">yyyy-MM-dd</prop>

  116. <prop key="time_format">HH:mm:ss</prop>

  117. <prop key="number_format">0.######</prop>

  118. <prop key="whitespace_stripping">true</prop>

  119. </props>

  120. </property>
  121. </bean>


  122. <!-- session持有者 -->

  123. <bean id="sessionProvider" class="com.itrip.rp.session.HttpSessionProvider" />

  124. <!-- spring上下文工具类 -->

  125. <bean id="springContextUtil " class="com.itrip.rp.utils.SpringContextUtil" />

  126. <!-- 数据库配置 -->

  127. <import resource="classpath:resources/database-context.xml"/>

  128. </beans>

这里要重点说明的就是之前提到过的spring上下文工具类:SpringContextUtil.java

  1. package com.itrip.rp.utils;



  2. import org.springframework.beans.BeansException;

  3. import org.springframework.beans.factory.NoSuchBeanDefinitionException;

  4. import org.springframework.context.ApplicationContext;

  5. import org.springframework.context.ApplicationContextAware;



  6. /**

  7. * spring上下文工具类

  8. *

  9. * @author Benny

  10. *

  11. */

  12. public class SpringContextUtil implements ApplicationContextAware {



  13. private static ApplicationContext applicationContext; // Spring应用上下文环境



  14. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

  15. SpringContextUtil.applicationContext = applicationContext;

  16. }



  17. public static ApplicationContext getApplicationContext() {

  18. return applicationContext;

  19. }



  20. public static Object getBean(String name) throws BeansException {

  21. return applicationContext.getBean(name);

  22. }



  23. public static Object getBean(Class<?> requiredType) throws BeansException {

  24. return applicationContext.getBean(requiredType);

  25. }



  26. public static Object getBean(String name, Class<?> requiredType) throws BeansException {

  27. return applicationContext.getBean(name, requiredType);

  28. }



  29. public static boolean containsBean(String name) {

  30. return applicationContext.containsBean(name);

  31. }



  32. public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {

  33. return applicationContext.isSingleton(name);

  34. }



  35. public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {

  36. return applicationContext.getType(name);

  37. }



  38. public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {

  39. return applicationContext.getAliases(name);

  40. }

  41. }

至此,springmvc+shiro安全管理+freemarker标签权限验证就完成了。

基于URL权限验证的方式也非常简单,只需要在自定义拦截器中对所有url进行权限校验即可,同样也是使用shiro权限校验机制,跟freemarker标签式的权限校验一致,看看拦截器源代码:

  1. package com.itrip.rp.interceptor;



  2. import javax.servlet.http.HttpServletRequest;

  3. import javax.servlet.http.HttpServletResponse;



  4. import org.apache.shiro.SecurityUtils;

  5. import org.apache.shiro.subject.Subject;

  6. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

  7. import org.springframework.web.util.UrlPathHelper;



  8. /**

  9. * URI拦截器 用户权限验证

  10. *

  11. * @author Benny

  12. */

  13. public class AdminContextInterceptor extends HandlerInterceptorAdapter {


  14. @Override

  15. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

  16. // 获取请求链接

  17. String uri = getURI(request);

  18. // 排除例外URI,例如:登陆、退出

  19. if (exclude(uri)) {

  20. return true;

  21. }

  22. Subject subject = SecurityUtils.getSubject();

  23. boolean pass = subject.isPermitted(uri);

  24. if (pass) {

  25. return true;

  26. } else {

  27. // 跳转至异常处理

  28. throw new Exception();

  29. }

  30. }
  31.  
  32. /**

  33. * 判断是否例外uri

  34. *

  35. * @param uri

  36. * @return

  37. */

  38. private boolean exclude(String uri) {

  39. if (excludeUrls != null) {

  40. for (String exc : excludeUrls) {

  41. // 允许以excludeurl结尾的请求

  42. if (uri.endsWith(exc)) {

  43. return true;

  44. }

  45. }

  46. }

  47. return false;

  48. }



  49. /**

  50. * 获取请求URL

  51. *

  52. * @param request

  53. * @author Benny

  54. * @return

  55. */

  56. private static String getURI(HttpServletRequest request) {

  57. UrlPathHelper helper = new UrlPathHelper();

  58. return helper.getOriginatingRequestUri(request);

  59. }



  60. private String[] excludeUrls;



  61. public void setExcludeUrls(String[] excludeUrls) {

  62. this.excludeUrls = excludeUrls;

  63. }

  64. }

以上实现了shiro安全管理+freemarker标签式的权限控制+系统全局url权限控制,基本满足大部分web项目的权限管理。

到此结束!

使用的jar包以及版本在此说明一下:

shiro相关jar包:

  1. <!-- shiro配置start -->

  2. <dependency>

  3. <groupId>org.apache.shiro</groupId>

  4. <artifactId>shiro-web</artifactId>

  5. <version>1.2.2</version>

  6. </dependency>



  7. <dependency>
  8. <groupId>org.apache.shiro</groupId>
  9. <artifactId>shiro-ehcache</artifactId>
  10. <version>1.2.2</version>
  11. </dependency>


  12. <dependency>
  13. <groupId>org.apache.shiro</groupId>

  14. <artifactId>shiro-quartz</artifactId>

  15. <version>1.2.2</version>

  16. </dependency>

  17. <dependency>

  18. <groupId>org.apache.shiro</groupId>

  19. <artifactId>shiro-spring</artifactId>

  20. <version>1.2.2</version>

  21. </dependency>

  22. <!-- shiro配置end -->

spring使用版本为3.0.5

  1. </div>

springmvc+shiro+freemarker实现的安全及权限管理的更多相关文章

  1. 基于shiro+jwt的真正rest url权限管理,前后端分离

    代码地址如下:http://www.demodashi.com/demo/13277.html bootshiro & usthe bootshiro是基于springboot+shiro+j ...

  2. 【shiro】(2)---基于RUL的权限管理

    基于RUL的权限管理 我想在写shiro权限管理认证前,先来一个基于URL实现的权限管理控制. 一.基于URI的权限业务逻辑  实现思路:       将系统操作的每个url配置在权限表中,将权限对应 ...

  3. Shiro集成SSM基于动态URL权限管理(二)

    这个案例基于上一个demo扩展而来.所以数据库表,在Shiro集成SSM基于URL权限管理(一)开篇的一致.如果上个demo操作的建议重新导入一次,避免出现问题. 而这次都不是通过固定写在方法上的注解 ...

  4. SpringMVC拦截器2(资源和权限管理)(作为补充说明)

    SpringMVC拦截器(资源和权限管理) 1.DispatcherServlet SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServle ...

  5. 《shiro》视频目录---1、权限管理-shiro

    \day01_shiro\0323\10realm支持散列.avi;\day01_shiro\0323\1权限管理原理.avi;\day01_shiro\0323\2权限管理解决方案.avi;\day ...

  6. Springmvc+Shiro实战

    原文链接:http://blog.csdn.net/qq_37936542/article/details/79010449 springmvc+shiro实现系统粗细粒度的权限管理步骤: 1:表格设 ...

  7. 7. 整合shiro,搭建粗粒度权限管理

    shiro是一个易用的权限管理框架,只需提供一个Realm即可在项目中使用,本文就将结合上一篇中搭建的权限模块.角色模块和用户模块来搭建一个粗粒度的权限管理系统,具体如下:1. 添加shiro依赖和与 ...

  8. springboot学习笔记:11.springboot+shiro+mysql+mybatis(通用mapper)+freemarker+ztree+layui实现通用的java后台管理系统(权限管理+用户管理+菜单管理)

    一.前言 经过前10篇文章,我们已经可以快速搭建一个springboot的web项目: 今天,我们在上一节基础上继续集成shiro框架,实现一个可以通用的后台管理系统:包括用户管理,角色管理,菜单管理 ...

  9. SpringMVC+Shiro权限管理【转】

    1.权限的简单描述 2.实例表结构及内容及POJO 3.Shiro-pom.xml 4.Shiro-web.xml 5.Shiro-MyShiro-权限认证,登录认证层 6.Shiro-applica ...

随机推荐

  1. 线段树 hdu3642 Get The Treasury

    不得不说,这是一题很经典的体积并.. 然而还是debug了2个多小时... 首先思路:按z的大小排序. 然后相当于扫描面一样,,从体积的最下方向上方扫描,遇到这个面 就将相应的两条线增加到set中,或 ...

  2. 【Android界面实现】使用GestureOverlayView控件实现手势识别

    在Android开发中,我们不光能够使用已有的实现方式.并且,我们还能够利用Android这个智能手机平台.实现一些比較有特色的功能. 本篇文章介绍使用GestureOverlayView这个控件.实 ...

  3. C++对象模型——Inline Functions(第四章)

    4.5 Inline Functions 以下是Point class 的一个加法运算符的可能实现内容: class Point { friend Point operator+(const Poin ...

  4. Python画图工具matplotlib的安装

    今天在机子上安装matplotlib遇到一些问题,特将此记录下来,供大家分享以少走弯路. 1:下载matplotlib 去官网上下载你所须要的版本号http://matplotlib.org/down ...

  5. jquery05 继承

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  6. Onvif开发之客户端鉴权获取参数篇

    前面一篇已经介绍了客户端如何发些设备,下面这篇简单介绍下在发现设备后,如何通过ONVIF协议来获取设备的相关参数 ONVIF中不管是客户端还是设备端,最先实现的接口都是关于能力的那个接口,在客户端实现 ...

  7. Css学习总结(1)——20个很有用的CSS技巧

    1. 黑白图像 这段代码会让你的彩色照片显示为黑白照片,是不是很酷? img.desaturate { filter: grayscale(100%); -webkit-filter: graysca ...

  8. 将已有的Eclipse项目转化为Maven项目

    将已有的Eclipse项目转化为Maven项目 我们之前在Eclipse IDE完成的Java命令行项目.Java Web项目也使用了构建工具--Ant,它帮助我们编译.运行Java源代码(无需我们自 ...

  9. [LuoguP4892]GodFly的寻宝之旅 状压DP

    链接 基础状压DP,预处理出sum,按照题意模拟即可 复杂度 \(O(n^22^n)\) #include<bits/stdc++.h> #define REP(i,a,b) for(in ...

  10. native.js是什么且如何使用

    native.js是什么且如何使用 一.总结 一句话总结:Native.js技术,简称NJS,是一种将手机操作系统的原生对象转义,映射为JS对象,在JS里编写原生代码的技术.Native.js不是一个 ...