1、用户表
1.1.1 用户表信息描述users
1.1.2 sql语句
CREATE TABLE users(
id varchar2(32) default SYS_GUID() PRIMARY KEY,
email VARCHAR2(50) UNIQUE NOT NULL,
username VARCHAR2(50),
PASSWORD VARCHAR2(50),
phoneNum VARCHAR2(20),
STATUS INT
)
1.2 角色表
1.2.1 角色表信息描述role
1.2.2 sql语句
CREATE TABLE role(
id varchar2(32) default SYS_GUID() PRIMARY KEY,
roleName VARCHAR2(50) ,
roleDesc VARCHAR2(50)
)
1.2.4 用户与角色关联关系
用户与角色之间是多对多关系,我们通过user_role表来描述其关联,在实体类中User中存在List,在Role中有List.
而角色与权限之间也存在关系,我们会在后面介绍。
CREATE TABLE users_role(
userId varchar2(32),
roleId varchar2(32),
PRIMARY KEY(userId,roleId),
FOREIGN KEY (userId) REFERENCES users(id),
FOREIGN KEY (roleId) REFERENCES role(id)
)
1.3 资源权限表
1.3.1 权限资源表描述permission
CREATE TABLE permission(
id varchar2(32) default SYS_GUID() PRIMARY KEY,
permissionName VARCHAR2(50) ,
url VARCHAR2(50)
)
1.3.4.权限资源与角色关联关系
权限资源与角色是多对多关系,我们使用role_permission表来描述。在实体类Permission中存在List,在Role类中
有List
CREATE TABLE role_permission
(
permissionId varchar2(32),
roleId varchar2(32),
PRIMARY KEY(permissionId,roleId),
FOREIGN KEY (permissionId)
REFERENCES permission(id),
FOREIGN KEY (roleId)
REFERENCES role(id)
)
2.1 Spring Security介绍
Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。
(https://projects.spring.io/spring-security/) Spring Security 为基于J2EE企业应用软件提供了全面安全服务。特别
是使用领先的J2EE解决方案-Spring框架开发的企业软件项目。
人们使用Spring Security有很多种原因,不过通常吸引他们的是在J2EE Servlet规范或EJB规范中找不到典型企业应用场景的解决方案。 特别要指出的是他们不能再
WAR 或 EAR 级别进行移植。
这样,如果你更换服务器环境,就要,在新的目标环境进行大量的工作,对你的应用
系统进行重新配 置安全。
使用Spring Security 解决了这些问题,也为你提供很多有用的,完全可以指定的其他安
全特性。 安全包括两个主要操作。
“认证”,是为用户建立一个他所声明的主体。主题一般式指用户,设备或可以在你系 统中执行动作的其他系
统。
“授权”指的是一个用户能否在你的应用中执行某个操作,在到达授权判断之前,身份的主题已经由 身份验证
过程建立了。
这些概念是通用的,不是Spring Security特有的。
在身份验证层面,Spring Security广泛支持各种身份验证模式,
这些验证模型绝大多数都由第三方提供,或则正在开发的有关标准机构提供的,例如 Internet Engineering Task
Force.作为补充,Spring Security 也提供了自己的一套验证功能。
Spring Security 目前支持认证一体化如下认证技术:
HTTP BASIC authentication headers (一个基于IEFT RFC 的
标准) HTTP Digest authentication headers (一个基于IEFT RFC 的标准)
HTTP X.509 client certificate exchange
(一个基于IEFT RFC 的标准) LDAP (一个非常常见的跨平台认证需要做法,特别是在大环境)
Form-based
authentication (提供简单用户接口的需求) OpenID authentication Computer Associates Siteminder JA-SIG
Central Authentication Service (CAS,这是一个流行的开源单点登录系统) Transparent authentication context
propagation for Remote Method Invocation and HttpInvoker (一个Spring远程调用协议)
1、创建login.jsp
<%@ page language=“java” contentType=“text/html; charset=UTF-8”
pageEncoding=“UTF-8”%>
<meta
content=“width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no”
name=“viewport”>
href=“${pageContext.request.contextPath}/plugins/bootstrap/css/bootstrap.min.css”>
href=“${pageContext.request.contextPath}/plugins/font-awesome/css/font-awesome.min.css”>
href=“${pageContext.request.contextPath}/plugins/ionicons/css/ionicons.min.css”>
href=“${pageContext.request.contextPath}/plugins/adminLTE/css/AdminLTE.css”>
href=“${pageContext.request.contextPath}/plugins/iCheck/square/blue.css”>
登录系统
<input type=“text” name=“username” class=“form-control”
placeholder=“用户名”> <span
class=“glyphicon glyphicon-envelope form-control-feedback”>
<input type=“password” name=“password” class=“form-control”
placeholder=“密码”> <span
class=“glyphicon glyphicon-lock form-control-feedback”>
登录
2、创建登录失败的页面:failer.jsp
<%@ page language=“java” contentType=“text/html; charset=UTF-8”
pageEncoding=“UTF-8”%>
<meta
content=“width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no”
name=“viewport”>
href=“${pageContext.request.contextPath}/plugins/bootstrap/css/bootstrap.min.css”>
href=“${pageContext.request.contextPath}/plugins/font-awesome/css/font-awesome.min.css”>
href=“${pageContext.request.contextPath}/plugins/ionicons/css/ionicons.min.css”>
href=“${pageContext.request.contextPath}/plugins/iCheck/square/blue.css”>
href=“${pageContext.request.contextPath}/plugins/morris/morris.css”>
href=“${pageContext.request.contextPath}/plugins/jvectormap/jquery-jvectormap-1.2.2.css”>
href=“${pageContext.request.contextPath}/plugins/datepicker/datepicker3.css”>
href=“${pageContext.request.contextPath}/plugins/daterangepicker/daterangepicker.css”>
href=“${pageContext.request.contextPath}/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.min.css”>
href=“${pageContext.request.contextPath}/plugins/datatables/dataTables.bootstrap.css”>
href=“${pageContext.request.contextPath}/plugins/treeTable/jquery.treetable.css”>
href=“${pageContext.request.contextPath}/plugins/treeTable/jquery.treetable.theme.default.css”>
href=“${pageContext.request.contextPath}/plugins/select2/select2.css”>
href=“${pageContext.request.contextPath}/plugins/colorpicker/bootstrap-colorpicker.min.css”>
href=“${pageContext.request.contextPath}/plugins/bootstrap-markdown/css/bootstrap-markdown.min.css”>
href=“${pageContext.request.contextPath}/plugins/adminLTE/css/AdminLTE.css”>
href=“${pageContext.request.contextPath}/plugins/adminLTE/css/skins/_all-skins.min.css”>
href=“${pageContext.request.contextPath}/css/style.css”>
href=“${pageContext.request.contextPath}/plugins/ionslider/ion.rangeSlider.css”>
href=“${pageContext.request.contextPath}/plugins/ionslider/ion.rangeSlider.skinNice.css”>
href=“${pageContext.request.contextPath}/plugins/bootstrap-slider/slider.css”>
数据
数据后台管理
<a href=“#” class=“sidebar-toggle” data-toggle=“offcanvas”
role=“button”> Toggle navigation
class=“dropdown-toggle” data-toggle=“dropdown”> <img
src=“${pageContext.request.contextPath}/img/user2-160x160.jpg”
class=“user-image” alt=“User Image”>
未登录
src=“${pageContext.request.contextPath}/img/user2-160x160.jpg”
class=“img-circle” alt=“User Image”>
<a href=“${pageContext.request.contextPath}/logout.do”
class=“btn btn-default btn-flat”>注销
<img src=“${pageContext.request.contextPath}/img/user2-160x160.jpg”
class=“img-circle” alt=“User Image”>
未登录
- 菜单
href=“${pageContext.request.contextPath}/pages/main.jsp”><i
class=“fa fa-dashboard”> 首页
系统管理 <i
class=“fa fa-angle-left pull-right”>
href=“${pageContext.request.contextPath}/user/findAll.do”> <i
class=“fa fa-circle-o”> 用户管理
角色管理
资源权限管理
href=“${pageContext.request.contextPath}/sysLog/findAll.do”> <i
class=“fa fa-circle-o”> 访问日志
基础数据 <i
class=“fa fa-angle-left pull-right”>
href=“${pageContext.request.contextPath}/product/findAll.do”>
产品管理
href=“${pageContext.request.contextPath}/order/findAll.do?page=1&pageSize=3”>
订单管理
登录失败 页面
class=“fa fa-dashboard”> 首页
- 登录失败
登录失败 , 你可以 返回到登录页面
重新登录
Version 1.0.8
Copyright © 2014-2017 <a
href=“http://www.itcast.cn”>研究院研发部.
All rights reserved.
3、在web.xml当中配置
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
4、创建spring-security.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:security=“http://www.springframework.org/schema/security”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<security:http pattern=“/login.jsp” security=“none”/>
<security:http pattern=“/failer.jsp” security=“none”/>
<security:http pattern=“/css/**” security=“none”/>
<security:http pattern=“/img/**” security=“none”/>
<security:http pattern=“/plugins/**” security=“none”/>
<security:http auto-config=“true” use-expressions=“false”>
<security:intercept-url pattern=“/**” access=“ROLE_USER,ROLE_ADMIN”/>
<security:form-login
login-page=“/login.jsp”
login-processing-url=“/login.do”
default-target-url=“/index.jsp”
authentication-failure-url=“/failer.jsp”
authentication-success-forward-url=“/pages/main.jsp”
/>
<security:csrf disabled=“true”/>
<security:logout invalidate-session=“true” logout-url=“/logout.do” logout-success-url=“/login.jsp” />
</security:http>
security:authentication-manager
<security:authentication-provider user-service-ref=“userService”>
<security:password-encoder ref=“passwordEncoder”/>
</security:authentication-provider>
</security:authentication-manager>
5、修改web.xml
contextConfigLocation
classpath*:applicationContext.xml,classpath*:spring-security.xml
6、创建接口IUserService
package com.itzheng.ssm.service;
import org.springframework.security.core.userdetails.UserDetailsService;
public interface IUserService extends UserDetailsService {
}
7、创建一个类UserServiceImpl
package com.itzheng.ssm.service.impl;
import com.itzheng.ssm.service.IUserService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service(“userService”)
@Transactional
public class UserServiceImpl implements IUserService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
}
8、创建UserInfo类
package com.itzheng.ssm.domain;
//与数据库中users对应
public class UserInfo {
private String id;
private String username;
private String email;
private String password;
private String phoneNum;
private int status;
private String statusStr;
private List roles;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getStatusStr() {
return statusStr;
}
public void setStatusStr(String statusStr) {
this.statusStr = statusStr;
}
public List getRoles() {
return roles;
}
public void setRoles(List roles) {
this.roles = roles;
}
}
9、创建Permission类
package com.itzheng.ssm.domain;
import java.util.List;
public class Permission {
private String id;
private String permissionName;
private String url;
private List roles;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPermissionName() {
return permissionName;
}
public void setPermissionName(String permissionName) {
this.permissionName = permissionName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public List getRoles() {
return roles;
}
public void setRoles(List roles) {
this.roles = roles;
}
}
10、创建IUserDao接口
package com.itzheng.ssm.dao;
import com.itzheng.ssm.domain.UserInfo;
import org.apache.ibatis.annotations.Select;
public interface IUserDao {
@Select(“select * from users where username=#{username}”)
public UserInfo findByUsername(String username) throws Exception;
}
11、修改UserServiceImpl的loadUserByUsername方法
package com.itzheng.ssm.service.impl;
import com.itzheng.ssm.dao.IUserDao;
import com.itzheng.ssm.domain.UserInfo;
import com.itzheng.ssm.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service(“userService”)
@Transactional
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
userInfo = userDao.findByUsername(username);
} catch (Exception e) {
e.printStackTrace();
}
//处理自己的用户对象封装成UserDetails
User user = new User(userInfo.getUsername(),userInfo.getPassword(),null);
return user;
}
}
运行以后登录失败
12、修改UserServiceImpl
//作用就是返回一个list的集合。而集合当中装入的就是角色的描述
public List getAuthority() {
List list = new ArrayList<>();
list.add(new SimpleGrantedAuthority(“ROLE_USER”));
return list;
}
再次运行项目
解决以上问题
User user = new User(userInfo.getUsername(), “{noop}”+userInfo.getPassword(), getAuthority());
13、查询用户的时候查询对应的角色
(1)创建 IRoleDao接口
package com.itzheng.ssm.dao;
import com.itzheng.ssm.domain.Role;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface IRoleDao {
//根据用户的id查询出所有用户的角色(通过中间表把所有userId 对应的 roleId 查询出来 在通过 roleId 查询对应的角色信息)
@Select(“select * from role where id in (select roleId from users_role where userId = #{userId})”)
public List findRoleByUserId(String userId) throws Exception;
}
(2)修改IUserDao设置Results(结果集)
package com.itzheng.ssm.dao;
import com.itzheng.ssm.domain.UserInfo;
import org.apache.ibatis.annotations.Many;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
public interface IUserDao {
@Select(“select * from users where username=#{username}”)
@Results({
@Result(id=true,property = “id”,column = “id”),
@Result(property = “username”,column = “username”),
@Result(property = “email”,column = “email”),
@Result(property = “password”,column = “password”),
@Result(property = “phoneNum”,column = “phoneNum”),
@Result(property = “status”,column = “status”),
@Result(property = “statusStr”,column = “statusStr”),
@Result(property = “roles”,column = “id”, javaType = java.util.List.class ,many = @Many(select = “com.itzheng.ssm.dao.IRoleDao.findRoleByUserId”))
})
public UserInfo findByUsername(String username) throws Exception;
}
(3)修改UserServiceImpl当中的loadUserByUsername方法和getAuthority方法
package com.itzheng.ssm.service.impl;
import com.itzheng.ssm.dao.IUserDao;
import com.itzheng.ssm.domain.Role;
import com.itzheng.ssm.domain.UserInfo;
import com.itzheng.ssm.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Service(“userService”)
@Transactional
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
userInfo = userDao.findByUsername(username);
} catch (Exception e) {
e.printStackTrace();
}
//处理自己的用户对象封装成UserDetails
User user = new User(userInfo.getUsername(), “{noop}”+userInfo.getPassword(), getAuthority(userInfo.getRoles()));
return user;
}
//作用就是返回一个list的集合。而集合当中装入的就是角色的描述
public List getAuthority(List roles) {
List list = new ArrayList<>();
for (Role role : roles){
list.add(new SimpleGrantedAuthority(“ROLE_”+role.getRoleName()));
}
return list;
}
}
14、在登录的时候处理非可用账号的处理
(1)修改UserServiceImpl当中的loadUserByUsername方法
User user = new User(userInfo.getUsername(),
userInfo.getPassword(),
userInfo.getStatus() == 0 ? false : true,
true,
true,
true,
getAuthority(userInfo.getRoles()));
15、运行测试
(1)默认是账号在可以用的状态
报错