初识Spring Security3感觉这个教程挺好就收藏了方便以后参考。
关于Spring Security学习的资料.
最重要,最齐全的中文资料当然是family168的中文文档
​​Spring Security2参考文档​​

​​Spring Security3 参考文档​​

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

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

需要添加的jar包:


我们先实现一个controller:

MainController.java


1. package
2.
3. import
4. import
5. import
6. import
7.
8. @Controller
9. @RequestMapping("/main")
10. public class
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
20. "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
31. "Received request to show admin page");
32. return "adminpage";
33.
34. }
35.
36. }



该controller有两个mapping映射:



引用



main/common

main/admin



现在我们将同过Spring Security3框架实现成功登陆的人都能访问到main/common.

但只有拥有admin权限的用户才能访问main/admin.



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


web.xml



1. <?xml versinotallow="1.0" encoding="UTF-8"?>
2. <web-app id="WebApp_ID" versinotallow="2.4"
3. xmlns="http://java.sun.com/xml/ns/j2ee"
4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5. xsi:schemaLocatinotallow="http://java.sun.com/xml/ns/j2ee
6. >
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.



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


1. <?xml versinotallow="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:schemaLocatinotallow="http://www.springframework.org/schema/beans
5. >
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.

1. <?xml versinotallow="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:cnotallow="http://www.springframework.org/schema/context"
5. xmlns:mvc="http://www.springframework.org/schema/mvc"
6. xsi:schemaLocatinotallow="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. >
12.
13. <!-- 激活spring的注解. -->
14. <context:annotation-config />
15.
16. <!-- 扫描注解组件并且自动的注入spring beans中.
17. >
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



1. <%@ page language="java" cnotallow="text/html; charset=UTF-8"
2. "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" cnotallow="text/html; charset=UTF-8">
7. <title>Insert title here</title>
8. </head>
9. <body>
10. <h1>Common Page</h1>
11. <p>每个人都能访问的页面.</p>
12. "/spring3-security-integration/main/admin"> Go AdminPage </a>
13. <br />
14. "/spring3-security-integration/auth/login">退出登录</a>
15.
16. </body>
17. </html>




adminpage.jsp


1. <%@ page language="java" cnotallow="text/html; charset=UTF-8"
2. "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" cnotallow="text/html; charset=UTF-8">
7. <title>Insert title here</title>
8. </head>
9. <body>
10. <h1>Admin Page</h1>
11. <p>管理员页面</p>
12. "/spring3-security-integration/auth/login">退出登录</a>
13. </body>
14. </html>



这两个JSP对应着










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









loginpage.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" cnotallow="text/html; charset=UTF-8"
6. "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" cnotallow="text/html; charset=UTF-8">
11. <title>Insert title here</title>
12. </head>
13. <body>
14.
15. <h1>Login</h1>
16.
17. "login-error">${error}</div>
18.
19. "../j_spring_security_check" method="post">
20.
21. <p>
22. "j_username">Username</label> <input id="j_username"
23. "j_username" type="text"
24. </p>
25.
26. <p>
27. "j_password">Password</label> <input id="j_password"
28. "j_password" type="password"
29. </p>
30.
31. "submit" value="Login"
32.
33. </form>
34.
35. </body>
36. </html>




deniedpage.jsp


1. <%@ page language="java" cnotallow="text/html; charset=UTF-8"
2. "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" cnotallow="text/html; charset=UTF-8">
7. <title>Insert title here</title>
8. </head>
9. <body>
10. <h1>你的权限不够!</h1>
11. <p>只有拥有Admin权限才能访问!</p>
12. "/spring3-security-integration/auth/login">退出登录</a>
13. </body>
14. </html>




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


LoginLogoutController.java



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



该controller实现了两个映射


引用



auth/login --显示Login页面

auth/denied --显示拒绝访问页面




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


spring-security.xml



1. <?xml versinotallow="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:schemaLocatinotallow="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. >
9.
10. <!-- Spring-Security 的配置 -->
11. <!-- 注意开启use-expressions.表示开启表达式.
12. see:http://www.family168.com/tutorial/springsecurity3/html/el-access.html
13. >
14. <security:http auto-cnotallow="true" use-expressinotallow="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-sessinotallow="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对应的三个权限


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。


所以


1. <security:intercept-url pattern="/auth/login" access="permitAll"/>


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




1. <security:intercept-url pattern="/main/admin" access="hasRole('ROLE_ADMIN')"/>
2. <security:intercept-url pattern="/main/common" access="hasRole('ROLE_USER')"/>


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







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





1. security:logout
2. invalidate-sessinotallow="true"
3. logout-success-url="/auth/login"
4. logout-url="/auth/logout"/>



很简单.我们开启了session失效功能.

注销URL为:/auth/logout

注销成功后转向:/auth/login




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



1. package
2.
3. public class
4.
5. private
6. private
7. private
8.
9. //getter/setter
10.
11. }




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


UserDao.java



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




自定义UserDetailsService .可以通过继承UserDetailsService

来达到灵活的自定义UserDetailsService


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



CustomUserDetailsService.java



1. package
2.
3. import
4. import
5. import
6.
7. import
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16. import
17.
18. /**
19. * 一个自定义的service用来和数据库进行操作. 即以后我们要通过数据库保存权限.则需要我们继承UserDetailsService
20. *
21. * @author liukai
22. *
23. */
24. public class CustomUserDetailsService implements
25.
26. protected static Logger logger = Logger.getLogger("service");
27.
28. private UserDao userDAO = new
29.
30. public
31. throws
32.
33. 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. new
47. true, true, true, true,
48. getAuthorities(dbUser.getAccess()));
49.
50. catch
51. "Error in retrieving user");
52. throw new UsernameNotFoundException("Error in retrieving user");
53. }
54.
55. return
56. }
57.
58. /**
59. * 获得访问角色权限
60. *
61. * @param access
62. * @return
63. */
64. public
65.
66. new ArrayList<GrantedAuthority>(2);
67.
68. // 所有的用户默认拥有ROLE_USER权限
69. "Grant ROLE_USER to this user");
70. new GrantedAuthorityImpl("ROLE_USER"));
71.
72. // 如果参数access为1.则拥有ROLE_ADMIN权限
73. if (access.compareTo(1) == 0) {
74. "Grant ROLE_ADMIN to this user");
75. new GrantedAuthorityImpl("ROLE_ADMIN"));
76. }
77.
78. return
79. }
80. }



最后启动服务器输入:

​​http://localhost:8080/spring3-security-integration/auth/login​​