SSM+Shiro
1) 表名:用户表(Sys_Users)

Salt:盐(佐料)。为避免被黑客等进行攻击(暴力密码破解),所以一般在注册用户信息时,系统会随机生成一个随机码。在验证时会将密码和随机码进行运算,以验证密码是否正确。
2) 表名:角色表(Sys_Role)

3) 表名:用户角色表(Sys_User_Role)

4) 表名:资源表(Sys_Resource)

5) 表名:角色权限表(Sys_Role_Permission)

RBAC:Role Basic Access Controll(基于角色的权限控制)
说明:权限验证的基本设计是5张表,扩展后可以设计为12张表
1) 导入jar包




常用的数据库连接池:
DBCP 、C3P0、BoneCP、Proxool、DDConnectionBroker、DBPool、XAPool、Primrose、SmartPool、MiniConnectionPoolManager及Druid等
Druid:
Druid连接池最大的优势是可以监控Sql语句的执行,为后期Sql语句的优化提供帮助。
2) 配置web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<!-- 1、过滤器 -->
<!-- characterEncodingFilter -->
<!-- 编码过滤器,对所有请求和响应进行编码处理 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <!-- HiddenHttpMethodFilter -->
<!--
响应只支持get和post,通过HiddenHttpMethodFilter可以将请求方式转为标准请求方式(解决put和delete不支持的问题)。
如果使用ResultFul必须配置
-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<!-- 对所有DispaccherServlet分配的任务进行过滤 -->
<servlet-name>springDispatcherServlet</servlet-name>
</filter-mapping> <!--
在web中使用shiro必须配置DelegatingFilterProxy过滤器(实现了Filter接口的Bean对象都会被DelegatingFilterProxy所代理)
targetFilterLifecycle:调用过滤器的init()和destroy()方法
注意:
filte-name的属性名必须和shiro中bean的Id相一致
-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 2、监听器 -->
<!-- ContextLoaderListener -->
<!--
用于监听web容器的启动,当web容器启动时自动对ApplicatoinContext信息进行装配
监听器实现了ServletContextListener接口
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- 可以去配置多个value值,各值之间使用","进行分隔 -->
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param> <!-- 3、Servlet -->
<!-- DispatcherServlet -->
<!-- 多所有请求进行拦截,然后根据请求资源的类型进行任务的分派 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> </web-app>
说明:
folder就是普通的文件夹,它和我们window下面使用的文件夹没有任何区别
source folder文件夹是一种特别的文件夹,是folder的子集,source folder中的代码会被编译且存放在web-inf/classes下
package也是特殊的文件夹,package是一种物理路径。通过"."区分上下级
3) 配置applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!-- 配置Shiro的核心组件(用于自动注入SecuriyManager) -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 1、配置缓存管理器 -->
<property name="cacheManager" ref="cacheManager"/>
<!-- 配置realm -->
<property name="realm" ref="realm"/>
</bean> <!-- 1)、配置缓存管理器:对会话的缓存进行管理 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean> <!-- 2)、配置Realm:实际进行验证的类 -->
<bean id="realm" class="cn.hl.realm.UserRealm">
</bean> <!-- 2、 自动调用过滤器的init()和destroy()方法-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean> <!-- 3、定义过滤器(配置一组过滤器) -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!-- 配置登录资源路径位置 -->
<property name="loginUrl" value="/login.jsp"/>
<!-- 配置登录成功跳转的资源路径位置(一般不需要配置。一般都是通过请求处理方法进行处理) -->
<!--
<property name="successUrl" value="/index.jsp"/>
-->
<!-- 配置无权限的跳转的资源路径位置 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!--
配置其它资源的访问控制
常用内置过滤器对象
anon :允许匿名访问
authc :需要通过认证才能访问
roles :需要具体角色才能访问
user :指定用户才能访问(较少使用)
logout :注销当前用户
-->
<property name="filterChainDefinitions">
<value>
/login.jsp=anon
/unauthorized.jsp=anon
/login =anon
/logout=logout # 其余资源需要经过认证后才能访问
/** = authc
</value>
</property>
</bean> </beans>
4) 配置spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 设置静态资源的访问控制 -->
<mvc:default-servlet-handler/> <!-- 启用注解 -->
<mvc:annotation-driven></mvc:annotation-driven> <!-- 配置自动扫描 -->
<context:component-scan base-package="cn.hl.controller"></context:component-scan> <!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
5) 编写Controller
@Controller
public class UserController {
@RequestMapping("login")
public String login(String account, String pwd){
System.out.println(SecurityUtils.getSubject());
System.out.println("account = " + account+" | pwd=" + pwd);
//执行登录验证
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(account,pwd); //判断用户是否已经登录(如果没有登录则执行登录验证)
if(!subject.isAuthenticated()){
try{
//执行登录验证
subject.login(token);
}
catch(AuthenticationException ex){
System.out.println("提示:" + ex.getMessage());
return "redirect:/login.jsp";
}
}
//已经登录则跳转到"index.jsp"页面
return "index";
}
}
6) 编写Realm
public class UserRealm extends AuthenticatingRealm{
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//1、获取用户信息(直接使用参数对象的Token需要进行转换)
//String username = String.valueOf(token.getPrincipal());
//2、将Token直接转换为UsernamePasswordToken(可以避免转换)
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
String username = userToken.getUsername();
//执行登录验证
System.out.println("通过数据库读取帐号信息");
//从数据库中读取到的内容
String user="admin";
//对账户名进行验证
//User user = service.getUserByAccount(username);
if(!user.equals(username)){
throw new UnknownAccountException("帐号信息不存在");
}
//数据库中读取到的密码(String credentials = user.getPassword())
String credentials = "123";
//对用户进行验证
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, credentials, getName());
return info;
}
}
盐
- 默认密码验证方式(直接进行比较)
[SimpleCredentialsMatcher]
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
//获取票证中的密码(用户提交的)
Object tokenCredentials = getCredentials(token);
//默认的原始密码(数据库中提取的)
Object accountCredentials = getCredentials(info);
return equals(tokenCredentials, accountCredentials);
}
- 缺点
² 同一个字符串加密加密后的结果是不变的
² 密码容易被破解
- 解决方案
在密码基础上加点"盐",加盐后可以使得密码破解的速度降低.
- 密码生成方式
//加密算法
String algorithmName ="MD5";
//加密次数
int hashIterations=1024; //定义盐
ByteSource salt = ByteSource.Util.bytes("hl"); //向数据库中存密码时,使用如下方式进行存储
//存储时可以考虑使用账号(+其他字段作为盐)
Object obj = new SimpleHash(algorithmName, "123", salt, hashIterations);
加入盐的验证
public class UserRealm extends AuthenticatingRealm{
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//1、获取用户信息(直接使用参数对象的Token需要进行转换)
//String username = String.valueOf(token.getPrincipal());
//2、将Token直接转换为UsernamePasswordToken(可以避免转换)
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
String username = userToken.getUsername();
//执行登录验证
System.out.println("通过数据库读取帐号信息");
//从数据库中读取到的内容
String user="admin";
//对账户名进行验证
//User user = service.getUserByAccount(username);
if(!user.equals(username)){
throw new UnknownAccountException("帐号信息不存在");
}
//数据库中读取到的密码(String credentials = user.getPassword())
//String credentials = "123";
//数据库中读取到的密码(数据库中存储的密码)
Object hashedCredentials= "e3076e0bf31c666de1bac66b6bbb35d6";
//盐
String salt = "hl";
ByteSource credentialsSalt = ByteSource.Util.bytes(salt.getBytes());
//e3076e0bf31c666de1bac66b6bbb35d6
//对用户进行验证(默认的匹配方式是直接进行比较)
//SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, credentials, getName());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
username,
hashedCredentials,
credentialsSalt,
getName());
return info;
}
}
【自定义角色】
1) 配置
<property name="filterChainDefinitions">
<value>
/login.jsp=anon
/unauthorized.jsp=anon
/login =anon
/logout=logout /add.jsp=roles[admin]
/update.jsp=roles["user,admin"]
/show.jsp=user[root] # 其余资源需要经过认证后才能访问
/** = authc
</value>
</property>
2) 授权
/**
* 不需要授权则直接继承类:AuthenticatingRealm
* 需要授权则需要继承类:AuthorizingRealm
* @author Terry
*
*/
public class UserRealm extends AuthorizingRealm{ /**
* 执行登录验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("1");
//1、获取用户信息(直接使用参数对象的Token需要进行转换)
//String username = String.valueOf(token.getPrincipal()); //2、将Token直接转换为UsernamePasswordToken(可以避免转换)
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
String username = userToken.getUsername(); //执行登录验证
System.out.println("通过数据库读取帐号信息");
//从数据库中读取到的内容
String user="admin"; //对账户名进行验证
//User user = service.getUserByAccount(username);
if(username==null){
throw new UnknownAccountException("帐号信息不存在");
} //数据库中读取到的密码(String credentials = user.getPassword())
//String credentials = "123";
//数据库中读取到的密码(数据库中存储的密码)
Object hashedCredentials= "e3076e0bf31c666de1bac66b6bbb35d6"; //盐
String salt = "hl";
ByteSource credentialsSalt = ByteSource.Util.bytes(salt.getBytes()); //e3076e0bf31c666de1bac66b6bbb35d6
//对用户进行验证(默认的匹配方式是直接进行比较)
//SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, credentials, getName());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
username,
hashedCredentials,
credentialsSalt,
getName());
return info;
} /**
* 执行授权操作
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
Set<String> roles=new HashSet<String>(); System.out.println("授权到用户......"); String username= String.valueOf(principals.getPrimaryPrincipal()); //从数据库中为不同用户读取角色
if("admin".equals(username)){
roles.add("admin");
roles.add("user");
}
else if("sa".equals(username)){
roles.add("user");
} SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//为用户设置角色(授权)
info.setRoles(roles);
return info;
}
}
【shiro标签】
1) 引入标签库
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
2) 应用标签库
<!-- 包含指定角色时显示元素向,否则将隐藏 -->
<shiro:hasRole name="admin">
<a href="add.jsp">add page</a>
</shiro:hasRole>
SSM+Shiro的更多相关文章
- SSM+shiro及相关插件的整合maven所有依赖,详细注释版,自用,持续更新
整合了SSM+shiro框架,slf4j+logback日志,及一些好用的插件PageHelper,mybatis-generator,Lombok,fastjson等等 <?xml versi ...
- Java中SSM+Shiro系统登录验证码的实现方法
1.验证码生成类: import java.util.Random; import java.awt.image.BufferedImage; import java.awt.Graphics; im ...
- 基于vue(element ui) + ssm + shiro 的权限框架
zhcc 基于vue(element ui) + ssm + shiro 的权限框架 引言 心声 现在的Java世界,各种资源很丰富,不得不说,从分布式,服务化,orm,再到前端控制,权限等等玲琅满目 ...
- 快速搭建springboot框架以及整合ssm+shiro+安装Rabbitmq和Erlang、Mysql下载与配置
1.快速搭建springboot框架(在idea中): file–>new project–>Spring Initializr–>next–>然后一直下一步. 然后复制一下代 ...
- springmvc SSM shiro redis 后台框架 多数据源 代码生成器
A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址 ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...
- 集成ssm+shiro出现的 问题
1.springmvc-servlet.xml .applicationContext.xml该如何配置include和exclude?,目前的做法是将.applicationContext.xml全 ...
- SSM+shiro,所有配置文件,详细注释版,自用
spring配置文件applicationContext.xml,放在resources下 <?xml version="1.0" encoding="UTF-8& ...
- 学生会管理系统(SSM)vue+ssm+shiro
数据库 drop database StudentUnionManagementSystem ; create database StudentUnionManagementSystem CHARAC ...
- Shiro第六篇【验证码、记住我】
验证码 在登陆的时候,我们一般都设置有验证码,但是我们如果使用Shiro的话,那么Shiro默认的是使用FormAuthenticationFilter进行表单认证. 而我们的验证校验的功能应该加在F ...
随机推荐
- 解决Error for wireless request "Set Mode" (8B06) 问题 (转载)
转自:http://blog.csdn.net/muge0913/article/details/17062871 在运行以下命令的时候,意外的出错,最后google了下,最终才确定了原因,因为在运行 ...
- bzoj 1707: [Usaco2007 Nov]tanning分配防晒霜【贪心||最大流(?)】
洛谷上能过的最大流bzoj上T了--但是贪心做法明明在洛谷上比最大流要慢啊--如果是最大流的话就是裸题了吧 说一下贪心,就按照防晒霜排序,然后对每一个防晒霜选一头可以使用的且r最小的牛 就,没了. 贪 ...
- Sql 主键设置
1.开发数据库时常用命名规范 1>.使用不包含数字的单数表名,如果必要的话可以增加模块名前缀. 2>.对于主键的命名,使用表名+ID的形式. 3>.作为外键的列的名字应该与它们所对应 ...
- SSH协议、HTTPS中SSL协议的完整交互过程
1.(SSH)公私钥认证原理 服务器建立公钥:每一次启动sshd服务时,该服务会主动去找/etc/ssh/ssh_host*的文件 客户端通过ssh工具进行连接,如Xshell,SecureCRT 服 ...
- excel 录入oracle 方法
http://blog.itpub.net/28602568/viewspace-1797410/ 1.方法1:外部表 1.将excel另存为.txt格式(2种txt 格式都可以),再传到数据库dir ...
- 405 Convert a Number to Hexadecimal 数字转换为十六进制数
给定一个整数,编写一个算法将这个数转换为十六进制数.对于负整数,我们通常使用 补码运算 方法.注意: 十六进制中所有字母(a-f)都必须是小写. 十六进制字符串中不能包含多余的前导零.如果 ...
- NHibernate3.2学习笔记
一.开发环境 数据库:SQLServer2008 编译器:VS2010 .Net版本:.Net Framework 4.0 二.涉及第三方程序集 NHibernate.dll:版本3.2 Iesi.C ...
- 6.13---example
example如何使用?简单查询这个例子展示了如何用生成后的Example类去生成一个简单的where子句: TestTableExample example = new TestTableExamp ...
- 1682. [HAOI2014]贴海报
1682. [HAOI2014]贴海报 ★★☆ 输入文件:ha14d.in 输出文件:ha14d.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] Byteto ...
- UVM基础之------uvm phases机制
代码的书写顺序会影响代码的实现,在不同的时间做不同的事情,这是UVM phase的设计哲学,UVM phase提供了一个通用的TB phase 解决方案.支持显示的隐式的同步方案,运行时刻的线程控制和 ...