zoukankan      html  css  js  c++  java
  • Spring Security笔记:使用数据库进行用户认证(form login using database)

    在前一节,学习了如何自定义登录页,但是用户名、密码仍然是配置在xml中的,这样显然太非主流,本节将学习如何把用户名/密码/角色存储在db中,通过db来实现用户认证

    一、项目结构

    与前面的示例相比,因为要连接db,所以多出了一个spring-database.xml用来定义数据库连接,此外,为了演示登录用户权限不足的场景,加了一个页面403.jsp,用来统一显示权限不足的提示信息

    二、数据库表结构(oracle环境)

     1 create table T_USERS
     2 (
     3   d_username VARCHAR2(50) not null,
     4   d_password VARCHAR2(60),
     5   d_enabled  NUMBER(1)
     6 );
     7 alter table T_USERS
     8   add constraint PK_USERS_USERNAME primary key (D_USERNAME) ;
     9   
    10 create table T_USER_ROLES
    11 (
    12   d_user_role_id NUMBER(10) not null,
    13   d_username     VARCHAR2(50),
    14   d_role         VARCHAR2(50)
    15 );
    16 alter table T_USER_ROLES
    17   add constraint PK_USER_ROLES primary key (D_USER_ROLE_ID);
    18 alter table T_USER_ROLES
    19   add constraint IDX_UNI_ROLE_USERNAME unique (D_USERNAME, D_ROLE);
    create-table

    这里创建了二张表,一张用来保存用户名/密码,另一张用来保存用户所属的权限角色,表名和字段名无所谓,可以随便改,但是用户表中,必须要有"用户名/密码/帐号的有效状态"这三列信息,权限角色表必须要有“用户名/权限角色”这二列信息

    再insert几条测试数据

     1 insert into T_USERS (D_USERNAME, D_PASSWORD, D_ENABLED)
     2 values ('YJMYZZ', '123456', 1);
     3 
     4 insert into T_USERS (D_USERNAME, D_PASSWORD, D_ENABLED)
     5 values ('MIKE', 'MIKE123', 1); 
     6 
     7 insert into T_USER_ROLES (D_USER_ROLE_ID, D_USERNAME, D_ROLE)
     8 values (1, 'MIKE', 'POWER');
     9 
    10 insert into T_USER_ROLES (D_USER_ROLE_ID, D_USERNAME, D_ROLE)
    11 values (2, 'YJMYZZ', 'ADMIN');
    12 
    13 insert into T_USER_ROLES (D_USER_ROLE_ID, D_USERNAME, D_ROLE)
    14 values (3, 'YJMYZZ', 'POWER');
    insert user/role data

    这里插入了二个用户YJMYZZ/MIKE,而且MIKE属于POWER组,YJMYZZ同时属于POWERADMIN二个权限组

    三、spring-security.xml

     1 <beans:beans xmlns="http://www.springframework.org/schema/security"
     2     xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3     xsi:schemaLocation="http://www.springframework.org/schema/beans
     4     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     5     http://www.springframework.org/schema/security
     6     http://www.springframework.org/schema/security/spring-security-3.2.xsd">
     7 
     8     <http auto-config="true" use-expressions="true">
     9         <intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
    10         <!-- access denied page -->
    11         <access-denied-handler error-page="/403" />
    12         <form-login login-page="/login" default-target-url="/welcome"
    13             authentication-failure-url="/login?error" username-parameter="username"
    14             password-parameter="password" />
    15         <logout logout-success-url="/login?logout" />
    16         <!-- enable csrf protection -->
    17         <csrf />
    18     </http>
    19 
    20     <!-- Select users and user_roles from database -->
    21     <authentication-manager>
    22         <authentication-provider>
    23             <jdbc-user-service data-source-ref="dataSource"
    24                 users-by-username-query="select d_username username,d_password password, d_enabled enabled from t_users where d_username=?"
    25                 authorities-by-username-query="select d_username username, d_role role from t_user_roles where d_username=?  " />
    26         </authentication-provider>
    27     </authentication-manager>
    28 
    29 </beans:beans>
    spring-security

    注意第9行,这里使用了一个el表达式,目的是/admin开头的url,必须有ADMIN角色的登录用户才可访问

    第11行,表示如果登录用户权限不够,将跳转到/403这个url

    24,25这二行,指定了查询用户/角色的sql语句,注意:虽然前面提到了用户/角色这二张表的表名/字段名可以随便写,但是写sql时,用户名的别名必须是username,密码列的别名必须是password,帐号有效状态的别名必须是enabled,而权限角色列的别名必须是role

    23行指定了db数据源,它的详细定义在 spring-database.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 
     5     http://www.springframework.org/schema/beans/spring-beans.xsd">
     6 
     7     <bean id="dataSource"
     8         class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     9         <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    10         <property name="url" value="jdbc:oracle:thin:@172.21.***.***:1521:orcl" />
    11         <property name="username" value="***" />
    12         <property name="password" value="***" />
    13     </bean>
    14 </beans>

    本文使用的是oracle数据库,如果是其它数据库,请自行调整上面的内容

    四、Controller 

     1 package com.cnblogs.yjmyzz;
     2 
     3 import org.springframework.security.authentication.AnonymousAuthenticationToken;
     4 import org.springframework.security.core.Authentication;
     5 import org.springframework.security.core.context.SecurityContextHolder;
     6 import org.springframework.security.core.userdetails.UserDetails;
     7 import org.springframework.stereotype.Controller;
     8 import org.springframework.web.bind.annotation.RequestMapping;
     9 import org.springframework.web.bind.annotation.RequestMethod;
    10 import org.springframework.web.bind.annotation.RequestParam;
    11 import org.springframework.web.servlet.ModelAndView;
    12 
    13 @Controller
    14 public class HelloController {
    15 
    16     @RequestMapping(value = { "/", "/welcome" }, method = RequestMethod.GET)
    17     public ModelAndView welcome() {
    18 
    19         ModelAndView model = new ModelAndView();
    20         model.addObject("title",
    21                 "Spring Security Login Form - Database Authentication");
    22         model.addObject("message", "This is default page!");
    23         model.setViewName("hello");
    24         return model;
    25 
    26     }
    27 
    28     @RequestMapping(value = "/admin", method = RequestMethod.GET)
    29     public ModelAndView admin() {
    30 
    31         ModelAndView model = new ModelAndView();
    32         model.addObject("title",
    33                 "Spring Security Login Form - Database Authentication");
    34         model.addObject("message", "This page is for ROLE_ADMIN only!");
    35         model.setViewName("admin");
    36         return model;
    37 
    38     }
    39 
    40     @RequestMapping(value = "/login", method = RequestMethod.GET)
    41     public ModelAndView login(
    42             @RequestParam(value = "error", required = false) String error,
    43             @RequestParam(value = "logout", required = false) String logout) {
    44 
    45         ModelAndView model = new ModelAndView();
    46         if (error != null) {
    47             model.addObject("error", "Invalid username and password!");
    48         }
    49 
    50         if (logout != null) {
    51             model.addObject("msg", "You've been logged out successfully.");
    52         }
    53         model.setViewName("login");
    54 
    55         return model;
    56 
    57     }
    58 
    59     // for 403 access denied page
    60     @RequestMapping(value = "/403", method = RequestMethod.GET)
    61     public ModelAndView accesssDenied() {
    62 
    63         ModelAndView model = new ModelAndView();
    64 
    65         // check if user is login
    66         Authentication auth = SecurityContextHolder.getContext()
    67                 .getAuthentication();
    68         if (!(auth instanceof AnonymousAuthenticationToken)) {
    69             UserDetails userDetail = (UserDetails) auth.getPrincipal();
    70             model.addObject("username", userDetail.getUsername());
    71         }
    72 
    73         model.setViewName("comm/403");
    74         return model;
    75 
    76     }
    77 
    78 }
    HelloController

    66-71行演示了如何在服务端判断一个用户是否已经登录

    五、视图页面

    hello.jsp

     1 <%@ page language="java" contentType="text/html; charset=UTF-8"
     2     pageEncoding="UTF-8"%>
     3 <%@taglib prefix="sec"
     4     uri="http://www.springframework.org/security/tags"%>
     5 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
     6 <html>
     7 <head>
     8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     9 <title>${title}</title>
    10 </head>
    11 <body>
    12     <h1>Title : ${title}</h1>
    13     <h1>Message : ${message}</h1>
    14     <sec:authorize access="hasRole('POWER')">
    15         <!-- For login user -->
    16         <c:url value="/j_spring_security_logout" var="logoutUrl" />
    17         <form action="${logoutUrl}" method="post" id="logoutForm">
    18             <input type="hidden" name="${_csrf.parameterName}"
    19                 value="${_csrf.token}" />
    20         </form>
    21         <script>
    22             function formSubmit() {
    23                 document.getElementById("logoutForm").submit();
    24             }
    25         </script>
    26 
    27         <c:if test="${pageContext.request.userPrincipal.name != null}">
    28             <h2>
    29                 User : ${pageContext.request.userPrincipal.name} | <a
    30                     href="javascript:formSubmit()"> Logout</a> | <a href="admin">admin</a>
    31             </h2>
    32         </c:if>
    33     </sec:authorize>
    34 
    35     <sec:authorize access="isAnonymous()">
    36         <br />
    37         <h2>
    38             <a href="login">login</a>
    39         </h2>
    40     </sec:authorize>
    41 
    42 </body>
    43 </html>
    hello.jsp

    注意一下:14、27、35这三行,它们演示了如何在jsp端判断用户具有的角色权限、是否已登录等用法

    403.jsp

     1 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
     2 <html>
     3 <body>
     4     <h1>HTTP Status 403 - Access is denied</h1>
     5 
     6     <c:choose>
     7         <c:when test="${empty username}">
     8             <h2>You do not have permission to access this page!</h2>
     9         </c:when>
    10         <c:otherwise>
    11             <h2>
    12                 Username : ${username} <br /> You do not have permission to access
    13                 this page!
    14             </h2>
    15         </c:otherwise>
    16     </c:choose>
    17 
    18 </body>
    19 </html>
    403.jsp

    admin.jsp

     1 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
     2 <%@page session="true"%>
     3 <html>
     4 <body>
     5     <h1>Title : ${title}</h1>
     6     <h1>Message : ${message}</h1>
     7 
     8     <c:url value="/j_spring_security_logout" var="logoutUrl" />
     9     <form action="${logoutUrl}" method="post" id="logoutForm">
    10         <input type="hidden" name="${_csrf.parameterName}"
    11             value="${_csrf.token}" />
    12     </form>
    13     <script>
    14         function formSubmit() {
    15             document.getElementById("logoutForm").submit();
    16         }
    17     </script>
    18 
    19     <c:if test="${pageContext.request.userPrincipal.name != null}">
    20         <h2>
    21             Welcome : ${pageContext.request.userPrincipal.name} | <a
    22                 href="javascript:formSubmit()"> Logout</a> | <a href="welcome">welcome</a>
    23         </h2>
    24     </c:if>
    25 
    26 </body>
    27 </html>
    admin.jsp

    因为在xml中已经配置了/admin开头的请求url,必须具有ADMIN角色权限,所以admin.jsp端反而不用任何额外的判断了

    文中示例源代码下载:SpringSecurity-LoginForm-Database-XML.zip

    参考文章: Spring Security Form Login Using Database

  • 相关阅读:
    kafka基础
    springboot启动过程(3)-refresh方法
    springboot启动过程(2)-run方法
    springboot启动过程(1)-初始化
    springBoot数据库jpa+对接mybatis
    spirng boot web配置开发
    spring boot 入门
    jetty分析
    NIO/AIO
    使用jsPDF 和jspdf-autotable 导出中文表格页面
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/form-login-using-database-with-spring-security3.html
Copyright © 2011-2022 走看看