• 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表

  • 相关阅读:
    uni-app 基础
    react 的理解
    在 ios 系统中 transfrom 的其他属性对 rotate 有影响
    vue-cli3.0 进行项目的部署和构建
    react 生命周期
    typeScrip(五)泛型
    typeScrip(四)函数
    typeScrip(三) 类
    typeScrip(二)变量声明、解构
    javaScript 判断横竖屏
  • 原文地址:https://www.cnblogs.com/sqy123/p/7234674.html
Copyright © 2020-2023  润新知