spring security4.2.2的maven配置+spring-security配置详解+java源码+数据库设计

一、引子

      最近项目需要添加权限拦截,经讨论决定采用spring security4.2.2!废话少说直接上干货!

      spring security 4.2.2文档:http://docs.spring.io/spring-security/site/docs/4.2.2.RELEASE/reference/htmlsingle/#el-access-web

      spring security 3 中文2文档:http://www.mossle.com/docs/auth/html/index.html

二、pom.xml配置

      需要在pom.xml里配置spring security的依赖,可以通过http://mvnrepository.com/search?q=spring+securitye查询不同版本需要的spring的版本支持。

 1   <!--spring security  -->
 2         <dependency>
 3             <groupId>org.springframework.security</groupId>
 4             <artifactId>spring-security-core</artifactId>
 5             <version>4.2.2.RELEASE</version>
 6         </dependency>
 7         
 8         <dependency>
 9             <groupId>org.springframework.security</groupId>
10             <artifactId>spring-security-web</artifactId>
11             <version>4.2.2.RELEASE</version>
12         </dependency>
13         
14          <dependency>
15             <groupId>org.springframework.security</groupId>
16             <artifactId>spring-security-config</artifactId>
17             <version>4.2.2.RELEASE</version>
18         </dependency>
19         <dependency>
20             <groupId>org.springframework.security</groupId>
21             <artifactId>spring-security-taglibs</artifactId>
22             <version>4.2.2.RELEASE</version>
23         </dependency>

三、web.xml配置       

需要在web.xml中配置Spring Security控制权限过滤器,

1   <filter>  
2         <filter-name>springSecurityFilterChain</filter-name>  
3         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
4     </filter>  
5     <filter-mapping>  
6         <filter-name>springSecurityFilterChain</filter-name>  
7         <url-pattern>/*</url-pattern>  
8     </filter-mapping>  

四、spring-security.xml配置

下面最主要的就是spring-security.xml的配置了

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
  3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4     xmlns="http://www.springframework.org/schema/security"
  5     xsi:schemaLocation="http://www.springframework.org/schema/beans
  6             http://www.springframework.org/schema/beans/spring-beans.xsd
  7             http://www.springframework.org/schema/security
  8             http://www.springframework.org/schema/security/spring-security.xsd" >
  9     
 10     <!-- 打印调试信息,仅在开发环境中使用 -->
 11     <!-- <debug/> -->
 12     
 13     <!-- 不需要被拦截的请求 -->
 14     <http pattern="/loginPage" security="none"/>
 15     <http pattern="/scripts/**" security="none"/>
 16     
 17     <!-- 
 18         登录页面可以使用第一种:
 19         <http pattern="/login.jsp" security="none"></http>
 20         <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true" ......
 21         这种方式直接访问.jsp
 22         也可以使用Controller来控制,两种方式登录页面login.jsp的位置不一样!!!
 23         下面是第二种方式:
 24         <http pattern="/login" security="none"></http>
 25         <form-login login-page="/login" login-processing-url="/login" ......
 26         第一个配置告诉spring security,类似于/login的url请求不做过滤处理,而第二个配置信息又告诉spring security url为/login的post请求登录请求处理。正是这种冲突导致了405错误的发生。
 27         既然知道了错误原因,那么只要避免冲突就能解决这个问题:使登录页的请求和登录处理的请求不一致,然后只配置登录页的请求不做拦截处理.
 28         我采用的方法是使用默认的登录URL /login,修改登录页面跳转url为/loginPage。请自行修改代码和配置信息
 29         这样是不是就大工告成了呢?很遗憾,当你启动程序时,输出用户名和密码,不管正确与否,都会有404 Not Found等着你,这又是为什么呢?
 30         登录请求404错误
 31         首先,建议你看一下spring security自动生成的登录页源码,你会发现有如下代码
 32         <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
 33         对于什么是csrf,请自行参考网上的资料。
 34         spring security默认情况下csrf protection是开启的,由于我们的登录页没有配置csrf的相关信息,因此spring security内置的过滤器将此链接置为无效链接
 35         解决办法就是配置csrf protection为不可用状态,在配置文件中增加
 36         <csrf disabled="true"/>
 37     -->
 38     
 39     <!-- 
 40         1、<http auto-config="true">,他可以自动配置login form,BSIC 认证和logout URL 和logout services,如果没有特殊表明,这个的默认值是false。想要自己配置则设置为"true"
 41         2、Spring Security采用的是一种就近原则,就是说当用户访问的url资源满足多个intercepter-url时,系统将使用第一个符合条件的intercept-url进行权限控制
 42      -->
 43     <http  auto-config="true" use-expressions="true">
 44         <!--
 45             另一种权限表达式:
 46             <http use-expressions="false">
 47             <intercept-url pattern='/**' access='ROLE_USER' />
 48         -->
 49         <!-- 禁用CSRF保护,默认是启用 -->
 50         <csrf disabled="true"/>
 51         
 52         <anonymous enabled="false"/>
 53         
 54         <!-- 基于角色认证(必须拥有ROLE_XXX角色才能访问所有/**/XXX/**资源) -->
 55         <!-- 确保对功能URL访问都需要权限 -->
 56         <intercept-url pattern="/**/add/**" access="hasRole('ADD')"/>
 57         <intercept-url pattern="/**/update/**" access="hasRole('UPDATE')"/>
 58         <intercept-url pattern="/**/delete/**" access="hasRole('DELETE')"/>
 59         <intercept-url pattern="/**/download/**" access="hasRole('DOWNLOAD')"/>  
 60         <intercept-url pattern="/**/access/**" access="hasRole('ADMIN')"/>
 61         
 62         <!-- Ensures that any request to our application requires the user to be authenticated  -->
 63         <intercept-url pattern="/**" access="authenticated"/>
 64 
 65         
 66         <!-- 
 67             实现免登陆验证,默认有效时间是两周,启用rememberMe之后的两周内,用户都可以直接跳过系统,直接进入系统。
 68             实际上,Spring Security中的rememberMe是依赖cookie实现的,当用户在登录时选择使用rememberMe,系统就会在登录成功后将为用户生成一个唯一标识,并将这个标识保存进cookie中
 69             Spring Security生成的cookie名称是SPRING_SECURITY_REMEMBER_ME_COOKIE,它的内容是一串加密的字符串,
 70             当用户再次访问系统时,Spring Security将从这个cookie读取用户信息,并加以验证。如果可以证实cookie有效,就会自动将用户登录到系统中,并为用户授予对应的权限。
 71         -->
 72 
 73         <!--   
 74             <remember-me remember-me-parameter="remember-me"
 75             data-source-ref="dataSource"/>
 76             spring security还提供了remember me的另一种相对更安全的实现机制 :在客户端的cookie中,仅保存一个无意义的加密串(与用户名、密码等敏感数据无关),然后在db中保存该加密串-用户信息的对应关系,自动登录时,用cookie中的加密串,到db中验证,如果通过,自动登录才算通过。会自动在你的数据库里创建一个表:PERSISTENT_LOGINS。
 77             如果不加data-source-ref="dataSource",会将上述信息放在内存中!
 78             作者的项目有些特殊要求,所有采用了下面的方式:登录后要在myAuthenticationSuccessHandler做特殊的处理!
 79         -->
 80         <remember-me authentication-success-handler-ref="myAuthenticationSuccessHandler"/>
 81 
 82         <!-- 
 83             login-page : 表示用户登陆时显示我们自定义的登录页面
 84             authentication-failure-url : 登录认证失败转向的url,当用户输入的登录名和密码不正确时,系统将再次跳转到登录页面,并添加一个error=true参数作为登陆失败的标示,这个标识是我们自定义的。
 85             default-target-url : 登录认证成功转向的地址
 86          -->
 87         <form-login 
 88             login-page="/loginPage" 
 89             authentication-failure-url="/loginPage?error=true" 
 90             authentication-success-handler-ref="myAuthenticationSuccessHandler"  
 91         />
 92         
 93         <!-- 登出后,返回到登陆页面 -->
 94         <!--  <logout logout-success-url="/loginPage" logout-url="/logout"/>
 95                    delete-cookies="JSESSIONID":退出删除JSESSIONID
 96         -->
 97         <logout />
 98         <!-- 
 99             控制同步session的过滤器 
100             如果concurrency-control标签配置了error-if-maximum-exceeded="true",max-sessions="1",那么第二次登录时,是登录不了的。
101             如果error-if-maximum-exceeded="false",那么第二次是能够登录到系统的,
102             但是第一个登录的账号再次发起请求时,会跳转到expired-url配置的url中,
103             如果没有配置expired-url,则显示:
104             This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).
105             翻译过来意思就是说:这个会话已经过期(可能由于多个并发登录尝试相同的用户)
106          -->
107        
108         <session-management invalid-session-url="/loginPage" >
109             <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" expired-url="/loginPage"/>
110         </session-management>
111         
112         <!-- 指定自己的权限验证过滤器,首先走自己的的过滤器 myFilter,如果被拦截就报没有权限;
113              如果通过会走spring security自带的拦截器,即上面配置的权限配置!
114         -->
115         <custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myFilter"/>
116     </http>
117     
118     <!-- 权限认证Spring日志监听器  -->
119     <beans:bean class="org.springframework.security.authentication.event.LoggerListener"/>
120     <beans:bean class="org.springframework.security.access.event.LoggerListener"/>
121     
122     <!--
123              一个自定义的filter,必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性,
124          我们的所有控制将在这三个类中实现,解释详见具体配置。
125     -->
126     <beans:bean id="myFilter" class="com.tcbd.common.interceptor.MyFilterSecurityInterceptor" >
127         <beans:property name="authenticationManager" ref="authenticationManager" />
128         <beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean" />
129         <beans:property name="securityMetadataSource" ref="securityMetadataSource" />
130     </beans:bean>
131 
132     <!-- 验证配置,实现用户认证的入口,主要实现UserDetailsService接口即可  -->
133     <authentication-manager alias="authenticationManager" >
134         <authentication-provider ref="daoAuthenticationProvider" >
135         </authentication-provider> 
136     </authentication-manager>
137 
138     <beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
139         <beans:property name="userDetailsService" ref="myUserDetailService" />
140         <beans:property name="passwordEncoder" ref="passwordEncoder" />
141     </beans:bean>    
142     <!-- spring推荐的单向加密算法 -->
143     <beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
144     
145     <!-- 在这个类中,读入用户的密码,角色信息,是否锁定,账号是否过期等属性信息  -->
146     <beans:bean id="myUserDetailService" class="com.tcbd.common.interceptor.MyUserDetailService" />
147     
148     
149     <!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
150     <beans:bean id="myAccessDecisionManagerBean" class="com.tcbd.common.interceptor.MyAccessDecisionManager" ></beans:bean>
151 
152     <!-- 资源源数据定义,即定义某一资源可以被哪些角色访问 -->
153     <beans:bean id="securityMetadataSource" class="com.tcbd.common.interceptor.MyFilterSecurityMetadataSource" />
154     
155     <beans:bean id="myAuthenticationSuccessHandler" class="com.tcbd.common.interceptor.MyAuthenticationSuccessHandler"/>
156     
157 </beans:beans>

spring security为我们提供了三种通配符。
通配符:?
示例:/admin/g?t.jsp
匹配任意一个字符,/admin/g?t.jsp可以匹配/admin/get.jsp和/admin/got.jsp或是/admin/gxt.do。不能匹配/admin/xxx.jsp。
通配符:*
示例:/admin/*.jsp
匹配任意多个字符,但不能跨越目录。/*/index.jsp可以匹配/admin/index.jsp和/user/index.jsp,但是不能匹配/index.jsp和/user/test/index.jsp。
通配符:**
示例:/**/index.jsp
可以匹配任意多个字符,可以跨越目录,可以匹配/index.jsp,/admin/index.jsp,/user/admin/index.jsp和/a/b/c/d/index.jsp

五、自己的拦截器

1,读入用户的密码,角色信息,是否锁定,账号是否过期等属性信息 :MyUserDetailService 

 1 import java.util.ArrayList;
 2 import java.util.Collection;
 3 
 4 import javax.annotation.Resource;
 5 
 6 import org.apache.commons.lang.StringUtils;
 7 import org.apache.log4j.Logger;
 8 import org.springframework.dao.DataAccessException;
 9 import org.springframework.security.core.GrantedAuthority;
10 import org.springframework.security.core.authority.SimpleGrantedAuthority;
11 import org.springframework.security.core.userdetails.User;
12 import org.springframework.security.core.userdetails.UserDetails;
13 import org.springframework.security.core.userdetails.UserDetailsService;
14 import org.springframework.security.core.userdetails.UsernameNotFoundException;
15 
16 /**
17  * 从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等
18  * 
19  */
20 public class MyUserDetailService implements UserDetailsService {
21     @Resource
22     private UserService userService;
23 
24     /**
25      * 数据库交互获取用户拥有的权限角色,并设置权限
26      */
27     @Override
28     public UserDetails loadUserByUsername(String userCode) throws UsernameNotFoundException, DataAccessException {
29         // 根据登录用户名获取用户信息
30         Users user = new Users();
31         user.setUserCode(username);
32         user = userService.selectByModel(user);
33         if (null != user) {
34             // 存放权限
35             Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
36                 String action = user.getRole();
37                 if (StringUtils.isNotBlank(action)) {
38                     String[] roleaCtion = action.split(",");
39                     for (int i = 0; i < roleaCtion.length; i++) {
40                         SimpleGrantedAuthority auth = new SimpleGrantedAuthority(roleaCtion[i]);
41                         auths.add(auth);
42                     }
43                 }
44                 //spring security自带的User对象
45             User userDetails = new User(username, user.getPassword(), true, true, true, true, auths);
46             return userDetails;
47         }
48         return null;
49     }
50 }

2,定义某一资源可以被哪些角色访问:MyFilterSecurityMetadataSource

 1 import java.util.ArrayList;
 2 import java.util.Collection;
 3 import java.util.List;
 4 import java.util.Map;
 5 
 6 import javax.servlet.http.HttpServletRequest;
 7 
 8 import org.apache.log4j.Logger;
 9 import org.springframework.security.access.ConfigAttribute;
10 import org.springframework.security.access.SecurityConfig;
11 import org.springframework.security.web.FilterInvocation;
12 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
13 
14 public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
15     private static Logger logger = Logger.getLogger(MyFilterSecurityMetadataSource.class);
16 
17     public List<ConfigAttribute> getAttributes(Object object) {
18         FilterInvocation fi = (FilterInvocation) object;
19         HttpServletRequest request = fi.getRequest();
20         String requestUrl = fi.getRequest().getRequestURI();
21         List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();
22         // 所有URL对应的角色,应用启动就存放到静态资源里,得到的结果是:不同的URL下,包含的多个角色
23         Map<String, String> resRoles = Constant.URL_ROLES;
24 
25         for (Map.Entry<String, String> ent : resRoles.entrySet()) {
26             String url = ent.getKey();
27             String roles = ent.getValue();
28             //根据业务写自己的匹配逻辑
29             if(requestUrl.startsWith(url)){
30                 attributes.addAll(SecurityConfig.createListFromCommaDelimitedString(roles));
31             }
32         }
33         logger.debug("【"+request.getRequestURI()+"】 roles: "+attributes);
34         return attributes;
35     }
36 
37 
38     public Collection<ConfigAttribute> getAllConfigAttributes() {
39         return null;
40     }
41 
42     public boolean supports(Class<?> clazz) {
43         return FilterInvocation.class.isAssignableFrom(clazz);
44     }
45 }

3,访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源:MyAccessDecisionManager 

 1 import java.util.Collection;
 2 import java.util.Iterator;
 3 
 4 import org.apache.commons.logging.Log;
 5 import org.apache.commons.logging.LogFactory;
 6 import org.springframework.security.access.AccessDecisionManager;
 7 import org.springframework.security.access.AccessDeniedException;
 8 import org.springframework.security.access.ConfigAttribute;
 9 import org.springframework.security.access.SecurityConfig;
10 import org.springframework.security.authentication.InsufficientAuthenticationException;
11 import org.springframework.security.core.Authentication;
12 import org.springframework.security.core.GrantedAuthority;
13 
14 /**
15  * 在这种方法中,需要与configAttributes比较验证
16  * 1、一个对象是一个URL,一个过滤器被这个URL找到权限配置,并通过这里
17  * 2、如果没有匹配相应的认证,AccessDeniedException
18  * 
19  */
20 public class MyAccessDecisionManager implements AccessDecisionManager {
21 
22     private static final Log logger = LogFactory.getLog(MyAccessDecisionManager.class);
23     
24     /**
25      * 在这个类中,最重要的是decide方法,如果不存在对该资源的定义,直接放行; 否则,如果找到正确的角色,即认为拥有权限,并放行,否则throw
26      * new AccessDeniedException("no right");这样,就会进入上面提到的/accessDenied.jsp页面。
27      * @param authentication :当前用户所且有的角色
28      * @param object :当前请求的URL
29      * @param configAttributes :当前URL所且有的角色
30      */
31     @Override
32     public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
33             throws AccessDeniedException, InsufficientAuthenticationException {
34         // 资源所需的角色列表,如果角色列表为空,则放行!继续下一个拦截器。
35         if (configAttributes == null) {
36             return;
37         }
38         // 即将访问的资源URL,如 : /admin.jsp
39         logger.info("URL :"+object);
40         // 遍历所需的角色集合
41         Iterator<ConfigAttribute> ite = configAttributes.iterator();
42         while (ite.hasNext()) {
43             ConfigAttribute ca = ite.next();
44             // 该资源所需要的角色
45             String needRole = ((SecurityConfig) ca).getAttribute();
46             // authentication.getAuthorities()获取用户所拥有的角色列表,如:OLE_DEFULT
47             for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
48                 // 将资源所需要的角色与用户拥有的角色比较
49                 if (needRole.equals(grantedAuthority.getAuthority())) {
50                     // grantedAuthority is user's role.
51                     // 角色相同,直接放行
52                     return;
53                 }
54             }
55         }
56         // 否则,提示没有权限访问该资源
57         throw new AccessDeniedException("no right");
58     }
59 
60     @Override
61     public boolean supports(ConfigAttribute attribute) {
62         return true;
63     }
64 
65     @Override
66     public boolean supports(Class<?> clazz) {
67         return true;
68     }
69 
70 }

4,拦截器核心,MyFilterSecurityInterceptor

 1 import java.io.IOException;
 2 
 3 import javax.servlet.Filter;
 4 import javax.servlet.FilterChain;
 5 import javax.servlet.FilterConfig;
 6 import javax.servlet.ServletException;
 7 import javax.servlet.ServletRequest;
 8 import javax.servlet.ServletResponse;
 9 
10 import org.springframework.security.access.SecurityMetadataSource;
11 import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
12 import org.springframework.security.access.intercept.InterceptorStatusToken;
13 import org.springframework.security.web.FilterInvocation;
14 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
15 
16 /**
17  * 
18  */
19 public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor
20         implements Filter {
21     
22     private FilterInvocationSecurityMetadataSource securityMetadataSource;
23 
24     /* get、set方法 */
25     public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
26         return securityMetadataSource;
27     }
28 
29     public void setSecurityMetadataSource(
30             FilterInvocationSecurityMetadataSource securityMetadataSource) {
31         this.securityMetadataSource = securityMetadataSource;
32     }
33 
34     @Override
35     public Class<? extends Object> getSecureObjectClass() {
36         return FilterInvocation.class;
37     }
38 
39     @Override
40     public SecurityMetadataSource obtainSecurityMetadataSource() {
41         return this.securityMetadataSource;
42     }
43 
44     @Override
45     public void doFilter(ServletRequest request, ServletResponse response,
46             FilterChain chain) throws IOException, ServletException {
47         
48         FilterInvocation fi = new FilterInvocation(request, response, chain);
49         invoke(fi);
50     }
51 
52     public void invoke(FilterInvocation fi) throws IOException,
53             ServletException {
54         /**
55          * 最核心的代码就是@link InterceptorStatusToken token = super.beforeInvocation(fi);
56          * 它会调用我们定义的MyInvocationSecurityMetadataSource.getAttributes方法和MyAccessDecisionManager.decide方法
57          * 这一句,即在执行doFilter之前,进行权限的检查,而具体的实现已经交给@link MyAccessDecisionManager 了
58          */
59         InterceptorStatusToken token = super.beforeInvocation(fi);
60         try {
61             //继续走下一个拦截器,也就是org.springframework.security.web.access.intercept.FilterSecurityInterceptor
62             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
63         } finally {
64             super.afterInvocation(token, null);
65         }
66     }
67 
68     @Override
69     public void destroy() {
70 
71     }
72 
73     @Override
74     public void init(FilterConfig arg0) throws ServletException {
75 
76     }
77 
78 }

5,登录页面(需要自己改一些东西)

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8"%>
 3 <%@ taglib prefix='fmt' uri="http://java.sun.com/jsp/jstl/fmt" %>
 4 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 5 <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
 6 <!DOCTYPE html>
 7 <html lang="zh-CN">
 8   <head>
 9     <meta charset="utf-8">
10     <meta http-equiv="X-UA-Compatible" content="IE=edge">
11     <meta name="viewport" content="width=device-width, initial-scale=1">
12     <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
13     <meta name="description" content="">
14     <meta name="author" content="">
15     <link rel="icon" href="/favicon.ico">
16 
17     <title><fmt:message key="application.title"></fmt:message></title>
18 
19     <!-- Bootstrap core CSS -->
20     <link href="/scripts/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet">
21 
22     <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
23     <!-- Custom styles for this template -->
24     
25     <link href="/scripts/apps/css/signin.css" rel="stylesheet">
26     
27     <style type="text/css">
28     .tip {
29         font-size: 10px;
30         color: red;
31         text-align: center;
32     }
33     
34     </style>
35   </head>
36 
37   <body>
38     <div class="container">
39         <c:url var="loginUrl" value="/login" />
40       <form action="${loginUrl}" id="login_form" class="form-signin" method="post">
41           <div class="form-signin-heading text-center">
42             <h2 ><fmt:message key="application.title"></fmt:message></h2>
43           </div>
44           <div id="tip" class="tip"></div>
45           <c:if test="${param.error != null}">
46                 <span style="color:red">用户名或密码有误</span>
47         </c:if>
48         
49         <label for="inputEmail" class="sr-only">登录帐号</label>
50         <input type="text" id="inputUserCode" name="username" class="form-control" placeholder="登录帐号"  autofocus>
51            <label for="inputPassword" class="sr-only">登录密码</label>
52            <input type="password" id="inputPassword" name="password" class="form-control" placeholder="登录密码">
53         <div class="input-group input-sm">
54           <div class="checkbox">
55             <label><input type="checkbox" id="rememberme" name="remember-me" value="true"> 下次自动登录</label>  
56           </div>
57         </div>
58         <button id="login_button" class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
59       </form>
60 
61     </div> 
62  
63     <script src="/scripts/plugins/jQuery/jquery-2.2.3.min.js"></script>
64   </body>
65 </html>

在JSP中相应的操作按钮上加上如下标签,控制显示:

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%> 该标签一定要加上!!!
<sec:authorize access="hasRole('ADD')">
<a href="/XXX/add">增加</a>
</sec:authorize>

    数据库设计:user表里有roleId,role表,resource-role表,resource表

原文地址:https://www.cnblogs.com/sqy123/p/7234674.html