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 ...
随机推荐
- EasyUI之树形结构tree
转自:https://blog.csdn.net/ya_1249463314/article/details/70305730 版权声明:本文为博主原创文章,未经博主允许不得转载. https://b ...
- css实现左边div固定宽度,右边div自适应撑满剩下的宽度
(1)使用float <div class="use-float"> <div></div> <div></div> & ...
- redis 客户端工具 RedisDesktopManager
https://redisdesktop.com/download 可以查看到spring+redis 缓存的数据
- linux学习之路4 系统目录架构
linux树状文件系统结构 bin(binary) 保存可执行文件 也就是保存所有命令 boot 引导目录 保存所有跟系统有关的引导程序 其中Vmlinux文件最为重要,是系统内核 dev 保存所有的 ...
- 374 Guess Number Higher or Lower 猜数字大小
我们正在玩一个猜数字游戏. 游戏规则如下:我从 1 到 n 选择一个数字. 你需要猜我选择了哪个数字.每次你猜错了,我会告诉你这个数字是大了还是小了.你调用一个预先定义好的接口 guess(int n ...
- Sql2008事务日志已满处理
处理方式: USE [master] GO ALTER DATABASE gzl SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE gzl SET ...
- 安卓开发常用网络请求框架OkHttp、Volley、XUtils、Retrofit对比
网络请求框架总结1.xutils 此框架庞大而周全,这个框架可以网络请求,同时可以图片加载,又可以数据存储,又可以 View 注解,使用这种框架很方便,这样会使得你整个项目对它依赖性太强,万一 ...
- Android 简单的语音播报
不解释快上车 Main.class package com.example.myapp; import android.app.AlertDialog;import android.os.Bundle ...
- PHP开发心得一
1,php获得服务器时间 $time= date('Y-m-d H:i'); echo $time; 一般写法如上,但发现打印出来的时间小时数总数不对,和机器的时间差几个小时.查资料发现,要设定时区. ...
- windows服务器修改远程登录的端口+防火墙配置
话不多说,一个bat文件,快速修改注册表端口.你只需要做的是另外防火墙添加例外端口后重启即可.经测试2008-2012-2016-2019正常使用! @echo off rem 查找端口号 for / ...