Spring Security3 - MVC 整合教程 (初识Spring Security3)

最终的目标是整合Spring Security + Spring3MVC
完成类似于SpringSide3中mini-web的功能.

Spring Security是什么?

引用
Spring Security,这是一种基于Spring AOP和Servlet过滤器的安全框架。它提供全面的安全性解决方案,同时在Web请求级和方法调用级处理身份确认和授权。在Spring Framework基础上,Spring Security充分利用了依赖注入(DI,Dependency Injection)和面向切面技术。



关于Spring Security学习的资料.
最重要,最齐全的中文资料当然是family168的中文文档
Spring Security2参考文档

Spring Security3 参考文档

附件包含了一个很好的初入门的PDF教程.
最好是花30分钟先照着PDF上的教程一步一步的操作.
虽然没有实际的应用价值,但对初学者认识SpringSecurity3很有帮助.

我们的项目目录结构最终是:




需要添加的jar包:




我们先实现一个controller:

MainController.java

Java代码 复制代码 收藏代码
  1. package org.liukai.tutorial.controller; 
  2.  
  3. import org.apache.log4j.Logger; 
  4. import org.springframework.stereotype.Controller; 
  5. import org.springframework.web.bind.annotation.RequestMapping; 
  6. import org.springframework.web.bind.annotation.RequestMethod; 
  7.  
  8. @Controller 
  9. @RequestMapping("/main"
  10. public class MainController { 
  11.     protected static Logger logger = Logger.getLogger("controller"); 
  12.  
  13.     /**
  14.      * 跳转到commonpage页面
  15.      *
  16.      * @return
  17.      */ 
  18.     @RequestMapping(value = "/common", method = RequestMethod.GET) 
  19.     public String getCommonPage() { 
  20.         logger.debug("Received request to show common page"); 
  21.         return "commonpage"
  22.     } 
  23.  
  24.     /**
  25.      * 跳转到adminpage页面
  26.      *
  27.      * @return
  28.      */ 
  29.     @RequestMapping(value = "/admin", method = RequestMethod.GET) 
  30.     public String getAadminPage() { 
  31.         logger.debug("Received request to show admin page"); 
  32.         return "adminpage"
  33.  
  34.     } 
  35.  
package org.liukai.tutorial.controller;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/main")
public class MainController {
	protected static Logger logger = Logger.getLogger("controller");

	/**
	 * 跳转到commonpage页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/common", method = RequestMethod.GET)
	public String getCommonPage() {
		logger.debug("Received request to show common page");
		return "commonpage";
	}

	/**
	 * 跳转到adminpage页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/admin", method = RequestMethod.GET)
	public String getAadminPage() {
		logger.debug("Received request to show admin page");
		return "adminpage";

	}

}



该controller有两个mapping映射:

引用
main/common
main/admin



现在我们将同过Spring Security3框架实现成功登陆的人都能访问到main/common.
但只有拥有admin权限的用户才能访问main/admin.


我们先在web.xml中开启Spring3MVC和SpringSecurity3.

web.xml

Xml代码 复制代码 收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <web-app id="WebApp_ID" version="2.4" 
  3.     xmlns="http://java.sun.com/xml/ns/j2ee"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee  
  6.     http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> 
  7.      
  8.     <!-- SpringSecurity必须的filter --> 
  9.     <filter> 
  10.         <filter-name>springSecurityFilterChain</filter-name> 
  11.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
  12.     </filter> 
  13.  
  14.     <filter-mapping> 
  15.         <filter-name>springSecurityFilterChain</filter-name> 
  16.         <url-pattern>/*</url-pattern> 
  17.     </filter-mapping> 
  18.  
  19.     <context-param> 
  20.         <param-name>contextConfigLocation</param-name> 
  21.         <param-value> 
  22.         /WEB-INF/spring-security.xml 
  23.         /WEB-INF/applicationContext.xml 
  24.         </param-value> 
  25.     </context-param> 
  26.  
  27.     <servlet> 
  28.         <servlet-name>spring</servlet-name> 
  29.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
  30.         <load-on-startup>1</load-on-startup> 
  31.     </servlet> 
  32.  
  33.     <servlet-mapping> 
  34.         <servlet-name>spring</servlet-name> 
  35.         <url-pattern>/</url-pattern> 
  36.     </servlet-mapping> 
  37.  
  38.     <listener> 
  39.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
  40.     </listener> 
  41.  
  42. </web-app> 



要启用SpringSecurity3,我们需要完成以下两步:
1.在web.xml中声明DelegatingFilterProxy.

Xml代码 复制代码 收藏代码
  1. <filter-mapping> 
  2.         <filter-name>springSecurityFilterChain</filter-name> 
  3.         <url-pattern>/*</url-pattern> 
  4.     </filter-mapping> 



表示项目中所有路径的资源都要经过SpringSecurity.

2.导入指定的SpringSecurity配置 :spring-security.xml

关于spring-security.xml的配置.
我们把这个放到后面配置.以便更详细的讲解.

注意一点.最好是将DelegatingFilterProxy写在DispatcherServlet之前.否则
SpringSecurity可能不会正常工作.



在web.xml中我们定义servlet:spring.
按照惯例,我们必须声明一个spring-servle.xml
spring-servle.xml

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" xmlns:p="http://www.springframework.org/schema/p" 
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5.             http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 
  6.  
  7.     <!-- 定义一个视图解析器 --> 
  8.     <bean id="viewResolver" 
  9.         class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
  10.         p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" /> 
  11.  
  12. </beans> 



这个XML配置声明一个视图解析器.在控制器中会根据JSP名映射到/ WEB-INF/jsp中相应的位置.


然后创建一个applicationContext.xml.

applicationContext.xml.

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.     xmlns:context="http://www.springframework.org/schema/context" 
  5.     xmlns:mvc="http://www.springframework.org/schema/mvc" 
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  7.             http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
  8.             http://www.springframework.org/schema/context 
  9.             http://www.springframework.org/schema/context/spring-context-3.0.xsd 
  10.             http://www.springframework.org/schema/mvc  
  11.             http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 
  12.  
  13.     <!-- 激活spring的注解. --> 
  14.     <context:annotation-config /> 
  15.  
  16.     <!-- 扫描注解组件并且自动的注入spring beans中.  
  17.     例如,他会扫描@Controller 和@Service下的文件.所以确保此base-package设置正确. --> 
  18.     <context:component-scan base-package="org.liukai.tutorial" /> 
  19.  
  20.     <!-- 配置注解驱动的Spring MVC Controller 的编程模型.注:次标签只在 Servlet MVC工作! --> 
  21.     <mvc:annotation-driven /> 
  22.  
  23. </beans> 






接着是创建JSP页面

commonpage.jsp

Jsp代码 复制代码 收藏代码
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" 
  2.     pageEncoding="UTF-8"%> 
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"
  4. <html> 
  5. <head> 
  6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
  7. <title>Insert title here</title> 
  8. </head> 
  9. <body> 
  10.     <h1>Common Page</h1> 
  11.     <p>每个人都能访问的页面.</p> 
  12.     <a href="/spring3-security-integration/main/admin"> Go AdminPage </a> 
  13.     <br /> 
  14.     <a href="/spring3-security-integration/auth/login">退出登录</a> 
  15.  
  16. </body> 
  17. </html> 




adminpage.jsp

Jsp代码 复制代码 收藏代码
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" 
  2.     pageEncoding="UTF-8"%> 
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"
  4. <html> 
  5. <head> 
  6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
  7. <title>Insert title here</title> 
  8. </head> 
  9. <body> 
  10.     <h1>Admin Page</h1> 
  11.     <p>管理员页面</p> 
  12.     <a href="/spring3-security-integration/auth/login">退出登录</a> 
  13. </body> 
  14. </html> 



这两个JSP对应着







当然还有登陆页面和拒绝访问页面






loginpage.jsp

Jsp代码 复制代码 收藏代码
  1. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 
  2. <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%> 
  3. <%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%> 
  4.  
  5. <%@ page language="java" contentType="text/html; charset=UTF-8" 
  6.     pageEncoding="UTF-8"%> 
  7. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"
  8. <html> 
  9. <head> 
  10. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
  11. <title>Insert title here</title> 
  12. </head> 
  13. <body> 
  14.  
  15.     <h1>Login</h1> 
  16.  
  17.     <div id="login-error">${error}</div> 
  18.  
  19.     <form action="../j_spring_security_check" method="post"
  20.  
  21.         <p> 
  22.             <label for="j_username">Username</label> <input id="j_username" 
  23.                 name="j_username" type="text" /> 
  24.         </p> 
  25.  
  26.         <p> 
  27.             <label for="j_password">Password</label> <input id="j_password" 
  28.                 name="j_password" type="password" /> 
  29.         </p> 
  30.  
  31.         <input type="submit" value="Login" /> 
  32.  
  33.     </form> 
  34.  
  35. </body> 
  36. </html> 




deniedpage.jsp

Jsp代码 复制代码 收藏代码
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" 
  2.     pageEncoding="UTF-8"%> 
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"
  4. <html> 
  5. <head> 
  6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
  7. <title>Insert title here</title> 
  8. </head> 
  9. <body> 
  10.     <h1>你的权限不够!</h1> 
  11.     <p>只有拥有Admin权限才能访问!</p> 
  12.     <a href="/spring3-security-integration/auth/login">退出登录</a> 
  13. </body> 
  14. </html> 




还有一个controller用于映射上面两个JSP页面..

LoginLogoutController.java


Java代码 复制代码 收藏代码
  1. package org.liukai.tutorial.controller; 
  2.  
  3. import org.apache.log4j.Logger; 
  4. import org.springframework.stereotype.Controller; 
  5. import org.springframework.ui.ModelMap; 
  6. import org.springframework.web.bind.annotation.RequestMapping; 
  7. import org.springframework.web.bind.annotation.RequestMethod; 
  8. import org.springframework.web.bind.annotation.RequestParam; 
  9.  
  10. @Controller 
  11. @RequestMapping("auth"
  12. public class LoginLogoutController { 
  13.  
  14.     protected static Logger logger = Logger.getLogger("controller"); 
  15.  
  16.     /**
  17.      * 指向登录页面
  18.      */ 
  19.     @RequestMapping(value = "/login", method = RequestMethod.GET) 
  20.     public String getLoginPage( 
  21.             @RequestParam(value = "error", required = false) boolean error, 
  22.             ModelMap model) { 
  23.  
  24.         logger.debug("Received request to show login page"); 
  25.  
  26.         if (error == true) { 
  27.             // Assign an error message 
  28.             model.put("error"
  29.                     "You have entered an invalid username or password!"); 
  30.         } else
  31.             model.put("error", ""); 
  32.         } 
  33.         return "loginpage"
  34.  
  35.     } 
  36.  
  37.     /**
  38.      * 指定无访问额权限页面
  39.      *
  40.      * @return
  41.      */ 
  42.     @RequestMapping(value = "/denied", method = RequestMethod.GET) 
  43.     public String getDeniedPage() { 
  44.  
  45.         logger.debug("Received request to show denied page"); 
  46.  
  47.         return "deniedpage"
  48.  
  49.     } 
package org.liukai.tutorial.controller;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("auth")
public class LoginLogoutController {

	protected static Logger logger = Logger.getLogger("controller");

	/**
	 * 指向登录页面
	 */
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String getLoginPage(
			@RequestParam(value = "error", required = false) boolean error,
			ModelMap model) {

		logger.debug("Received request to show login page");

		if (error == true) {
			// Assign an error message
			model.put("error",
					"You have entered an invalid username or password!");
		} else {
			model.put("error", "");
		}
		return "loginpage";

	}

	/**
	 * 指定无访问额权限页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/denied", method = RequestMethod.GET)
	public String getDeniedPage() {

		logger.debug("Received request to show denied page");

		return "deniedpage";

	}
}



该controller实现了两个映射

引用
auth/login     --显示Login页面
auth/denied    --显示拒绝访问页面




最后,让我们看看spring-security.xml的配置

spring-security.xml

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.     xmlns:security="http://www.springframework.org/schema/security" 
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6.             http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
  7.             http://www.springframework.org/schema/security  
  8.             http://www.springframework.org/schema/security/spring-security-3.0.xsd"> 
  9.      
  10.     <!--  Spring-Security 的配置 --> 
  11.     <!-- 注意开启use-expressions.表示开启表达式. 
  12.     see:http://www.family168.com/tutorial/springsecurity3/html/el-access.html 
  13.      --> 
  14.     <security:http auto-config="true" use-expressions="true" access-denied-page="/auth/denied" > 
  15.          
  16.         <security:intercept-url pattern="/auth/login" access="permitAll"/> 
  17.         <security:intercept-url pattern="/main/admin" access="hasRole('ROLE_ADMIN')"/> 
  18.         <security:intercept-url pattern="/main/common" access="hasRole('ROLE_USER')"/> 
  19.          
  20.         <security:form-login 
  21.                 login-page="/auth/login"  
  22.                 authentication-failure-url="/auth/login?error=true"  
  23.                 default-target-url="/main/common"/> 
  24.              
  25.         <security:logout  
  26.                 invalidate-session="true"  
  27.                 logout-success-url="/auth/login"  
  28.                 logout-url="/auth/logout"/> 
  29.      
  30.     </security:http> 
  31.      
  32.     <!-- 指定一个自定义的authentication-manager :customUserDetailsService --> 
  33.     <security:authentication-manager> 
  34.             <security:authentication-provider user-service-ref="customUserDetailsService"> 
  35.                     <security:password-encoder ref="passwordEncoder"/> 
  36.             </security:authentication-provider> 
  37.     </security:authentication-manager> 
  38.      
  39.     <!-- 对密码进行MD5编码 --> 
  40.     <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/> 
  41.  
  42.     <!--  
  43.         通过 customUserDetailsService,Spring会自动的用户的访问级别. 
  44.         也可以理解成:以后我们和数据库操作就是通过customUserDetailsService来进行关联. 
  45.      --> 
  46.     <bean id="customUserDetailsService" class="org.liukai.tutorial.service.CustomUserDetailsService"/> 
  47.      
  48. </beans> 





在配置中我们可以看到三个URL对应的三个权限

Xml代码 复制代码 收藏代码
  1. <security:intercept-url pattern="/auth/login" access="permitAll"/> 
  2.         <security:intercept-url pattern="/main/admin" access="hasRole('ROLE_ADMIN')"/> 
  3.         <security:intercept-url pattern="/main/common" access="hasRole('ROLE_USER')"/> 



需要注意的是我们使用了SpringEL表达式来指定角色的访问.
以下是表达式对应的用法.

引用

表达式 说明
hasRole([role]) 返回 true 如果当前主体拥有特定角色。
hasAnyRole([role1,role2]) 返回 true 如果当前主体拥有任何一个提供的角色 (使用逗号分隔的字符串队列)
principal 允许直接访问主体对象,表示当前用户
authentication 允许直接访问当前 Authentication对象 从SecurityContext中获得
permitAll 一直返回true
denyAll 一直返回false
isAnonymous() 如果用户是一个匿名登录的用户 就会返回 true
isRememberMe() 如果用户是通过remember-me 登录的用户 就会返回 true
isAuthenticated() 如果用户不是匿名用户就会返回true
isFullyAuthenticated() 如果用户不是通过匿名也不是通过remember-me登录的用户时, 就会返回true。



所以

Xml代码 复制代码 收藏代码
  1. <security:intercept-url pattern="/auth/login" access="permitAll"/> 


表示所有的人都可以访问/auth/login.


Xml代码 复制代码 收藏代码
  1. <security:intercept-url pattern="/main/admin" access="hasRole('ROLE_ADMIN')"/> 
  2.         <security:intercept-url pattern="/main/common" access="hasRole('ROLE_USER')"/> 


则表示只有拥有对应的角色才能访问.





Xml代码 复制代码 收藏代码
  1. <security:form-login 
  2.         login-page="/auth/login"  
  3.         authentication-failure-url="/auth/login?error=true"  
  4.         default-target-url="/main/common"/> 



表示通过 /auth/login这个映射进行登录.
如果验证失败则返回一个URL:/auth/login?error=true
如果登录成功则默认指向:/main/common



Xml代码 复制代码 收藏代码
  1. security:logout  
  2.                 invalidate-session="true"  
  3.                 logout-success-url="/auth/login"  
  4.                 logout-url="/auth/logout"/> 



很简单.我们开启了session失效功能.
注销URL为:/auth/logout
注销成功后转向:/auth/login


Xml代码 复制代码 收藏代码
  1. <!-- 指定一个自定义的authentication-manager :customUserDetailsService --> 
  2.     <security:authentication-manager> 
  3.             <security:authentication-provider user-service-ref="customUserDetailsService"> 
  4.                     <security:password-encoder ref="passwordEncoder"/> 
  5.             </security:authentication-provider> 
  6.     </security:authentication-manager> 
  7.      
  8.     <!-- 对密码进行MD5编码 --> 
  9.     <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/> 
  10.  
  11.     <!--  
  12.         通过 customUserDetailsService,Spring会自动的用户的访问级别. 
  13.         也可以理解成:以后我们和数据库操作就是通过customUserDetailsService来进行关联. 
  14.      --> 
  15.     <bean id="customUserDetailsService" class="org.liukai.tutorial.service.CustomUserDetailsService"/> 



一个自定义的CustomUserDetailsService,是实现SpringSecurity的UserDetailsService接口,但我们重写了他即便于我们进行数据库操作.



DbUser.java

Java代码 复制代码 收藏代码
  1. package org.liukai.tutorial.domain; 
  2.  
  3. public class DbUser { 
  4.  
  5.     private String username; 
  6.     private String password; 
  7.     private Integer access; 
  8.  
  9.      //getter/setter 
  10.  
package org.liukai.tutorial.domain;

public class DbUser {

	private String username;
	private String password;
	private Integer access;

	 //getter/setter

}




通过一个初始化的List来模拟数据库操作.

UserDao.java

Java代码 复制代码 收藏代码
  1. package org.liukai.tutorial.dao; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.List; 
  5.  
  6. import org.apache.log4j.Logger; 
  7. import org.liukai.tutorial.domain.DbUser; 
  8.  
  9. public class UserDao { 
  10.  
  11.     protected static Logger logger = Logger.getLogger("dao"); 
  12.  
  13.     public DbUser getDatabase(String username) { 
  14.  
  15.         List<DbUser> users = internalDatabase(); 
  16.  
  17.         for (DbUser dbUser : users) { 
  18.             if (dbUser.getUsername().equals(username) == true) { 
  19.                 logger.debug("User found"); 
  20.                 return dbUser; 
  21.             } 
  22.         } 
  23.         logger.error("User does not exist!"); 
  24.         throw new RuntimeException("User does not exist!"); 
  25.  
  26.     } 
  27.  
  28.     /**
  29.      * 初始化数据
  30.      */ 
  31.     private List<DbUser> internalDatabase() { 
  32.  
  33.         List<DbUser> users = new ArrayList<DbUser>(); 
  34.         DbUser user = null
  35.  
  36.         user = new DbUser(); 
  37.         user.setUsername("admin"); 
  38.  
  39.         // "admin"经过MD5加密后 
  40.         user.setPassword("21232f297a57a5a743894a0e4a801fc3"); 
  41.         user.setAccess(1); 
  42.  
  43.         users.add(user); 
  44.  
  45.         user = new DbUser(); 
  46.         user.setUsername("user"); 
  47.  
  48.         // "user"经过MD5加密后 
  49.         user.setPassword("ee11cbb19052e40b07aac0ca060c23ee"); 
  50.         user.setAccess(2); 
  51.  
  52.         users.add(user); 
  53.  
  54.         return users; 
  55.  
  56.     } 
package org.liukai.tutorial.dao;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.liukai.tutorial.domain.DbUser;

public class UserDao {

	protected static Logger logger = Logger.getLogger("dao");

	public DbUser getDatabase(String username) {

		List<DbUser> users = internalDatabase();

		for (DbUser dbUser : users) {
			if (dbUser.getUsername().equals(username) == true) {
				logger.debug("User found");
				return dbUser;
			}
		}
		logger.error("User does not exist!");
		throw new RuntimeException("User does not exist!");

	}

	/**
	 * 初始化数据
	 */
	private List<DbUser> internalDatabase() {

		List<DbUser> users = new ArrayList<DbUser>();
		DbUser user = null;

		user = new DbUser();
		user.setUsername("admin");

		// "admin"经过MD5加密后
		user.setPassword("21232f297a57a5a743894a0e4a801fc3");
		user.setAccess(1);

		users.add(user);

		user = new DbUser();
		user.setUsername("user");

		// "user"经过MD5加密后
		user.setPassword("ee11cbb19052e40b07aac0ca060c23ee");
		user.setAccess(2);

		users.add(user);

		return users;

	}
}




自定义UserDetailsService .可以通过继承UserDetailsService
来达到灵活的自定义UserDetailsService

关于UserDetailsService更多信息. 可以查看SpringSecurity3文档


CustomUserDetailsService.java

Java代码 复制代码 收藏代码
  1. package org.liukai.tutorial.service; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.Collection; 
  5. import java.util.List; 
  6.  
  7. import org.apache.log4j.Logger; 
  8. import org.liukai.tutorial.dao.UserDao; 
  9. import org.liukai.tutorial.domain.DbUser; 
  10. import org.springframework.dao.DataAccessException; 
  11. import org.springframework.security.core.GrantedAuthority; 
  12. import org.springframework.security.core.authority.GrantedAuthorityImpl; 
  13. import org.springframework.security.core.userdetails.User; 
  14. import org.springframework.security.core.userdetails.UserDetails; 
  15. import org.springframework.security.core.userdetails.UserDetailsService; 
  16. import org.springframework.security.core.userdetails.UsernameNotFoundException; 
  17.  
  18. /**
  19. * 一个自定义的service用来和数据库进行操作. 即以后我们要通过数据库保存权限.则需要我们继承UserDetailsService
  20. *
  21. * @author liukai
  22. *
  23. */ 
  24. public class CustomUserDetailsService implements UserDetailsService { 
  25.  
  26.     protected static Logger logger = Logger.getLogger("service"); 
  27.  
  28.     private UserDao userDAO = new UserDao(); 
  29.  
  30.     public UserDetails loadUserByUsername(String username) 
  31.             throws UsernameNotFoundException, DataAccessException { 
  32.  
  33.         UserDetails user = null
  34.  
  35.         try
  36.  
  37.             // 搜索数据库以匹配用户登录名. 
  38.             // 我们可以通过dao使用JDBC来访问数据库 
  39.             DbUser dbUser = userDAO.getDatabase(username); 
  40.  
  41.             // Populate the Spring User object with details from the dbUser 
  42.             // Here we just pass the username, password, and access level 
  43.             // getAuthorities() will translate the access level to the correct 
  44.             // role type 
  45.  
  46.             user = new User(dbUser.getUsername(), dbUser.getPassword() 
  47.                     .toLowerCase(), true, true, true, true
  48.                     getAuthorities(dbUser.getAccess())); 
  49.  
  50.         } catch (Exception e) { 
  51.             logger.error("Error in retrieving user"); 
  52.             throw new UsernameNotFoundException("Error in retrieving user"); 
  53.         } 
  54.  
  55.         return user; 
  56.     } 
  57.  
  58.     /**
  59.      * 获得访问角色权限
  60.      *
  61.      * @param access
  62.      * @return
  63.      */ 
  64.     public Collection<GrantedAuthority> getAuthorities(Integer access) { 
  65.  
  66.         List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2); 
  67.  
  68.         // 所有的用户默认拥有ROLE_USER权限 
  69.         logger.debug("Grant ROLE_USER to this user"); 
  70.         authList.add(new GrantedAuthorityImpl("ROLE_USER")); 
  71.  
  72.         // 如果参数access为1.则拥有ROLE_ADMIN权限 
  73.         if (access.compareTo(1) == 0) { 
  74.             logger.debug("Grant ROLE_ADMIN to this user"); 
  75.             authList.add(new GrantedAuthorityImpl("ROLE_ADMIN")); 
  76.         } 
  77.  
  78.         return authList; 
  79.     } 
 package org.liukai.tutorial.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;
import org.liukai.tutorial.dao.UserDao;
import org.liukai.tutorial.domain.DbUser;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

/**
 * 一个自定义的service用来和数据库进行操作. 即以后我们要通过数据库保存权限.则需要我们继承UserDetailsService
 * 
 * @author liukai
 * 
 */
public class CustomUserDetailsService implements UserDetailsService {

	protected static Logger logger = Logger.getLogger("service");

	private UserDao userDAO = new UserDao();

	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException, DataAccessException {

		UserDetails user = null;

		try {

			// 搜索数据库以匹配用户登录名.
			// 我们可以通过dao使用JDBC来访问数据库
			DbUser dbUser = userDAO.getDatabase(username);

			// Populate the Spring User object with details from the dbUser
			// Here we just pass the username, password, and access level
			// getAuthorities() will translate the access level to the correct
			// role type

			user = new User(dbUser.getUsername(), dbUser.getPassword()
					.toLowerCase(), true, true, true, true,
					getAuthorities(dbUser.getAccess()));

		} catch (Exception e) {
			logger.error("Error in retrieving user");
			throw new UsernameNotFoundException("Error in retrieving user");
		}

		return user;
	}

	/**
	 * 获得访问角色权限
	 * 
	 * @param access
	 * @return
	 */
	public Collection<GrantedAuthority> getAuthorities(Integer access) {

		List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);

		// 所有的用户默认拥有ROLE_USER权限
		logger.debug("Grant ROLE_USER to this user");
		authList.add(new GrantedAuthorityImpl("ROLE_USER"));

		// 如果参数access为1.则拥有ROLE_ADMIN权限
		if (access.compareTo(1) == 0) {
			logger.debug("Grant ROLE_ADMIN to this user");
			authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
		}

		return authList;
	}
}




最后启动服务器输入:
http://localhost:8080/spring3-security-integration/auth/login



总结
通过本教程.我们对SpringSecurity3有了进一步的认识.
主要是了解了UserDetailsService的重要作用.
以及实现了模拟自定义数据的登录.(这点很重要,很多人学习了SpringSecurity却不知道
如何自定义权限)

这次教程因为内容很多,显得比较粗糙.很多地方并没有详细的阐明.
后面的教程还是SpringSecurity.
但我们将对SpringSecurity3新推出的一些特性进行详细的说明和理解.


BTW:附件为本次教程源码.你可以下载后直接在tomcat或其他web服务器启动.也可以自行添加
maven插件启动.

  • 大小: 23.5 KB
  • 大小: 18.4 KB
  • 大小: 4.6 KB
  • 大小: 5.8 KB
  • 大小: 4.2 KB
  • 大小: 8 KB

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值