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的更多相关文章

  1. SSM+shiro及相关插件的整合maven所有依赖,详细注释版,自用,持续更新

    整合了SSM+shiro框架,slf4j+logback日志,及一些好用的插件PageHelper,mybatis-generator,Lombok,fastjson等等 <?xml versi ...

  2. Java中SSM+Shiro系统登录验证码的实现方法

    1.验证码生成类: import java.util.Random; import java.awt.image.BufferedImage; import java.awt.Graphics; im ...

  3. 基于vue(element ui) + ssm + shiro 的权限框架

    zhcc 基于vue(element ui) + ssm + shiro 的权限框架 引言 心声 现在的Java世界,各种资源很丰富,不得不说,从分布式,服务化,orm,再到前端控制,权限等等玲琅满目 ...

  4. 快速搭建springboot框架以及整合ssm+shiro+安装Rabbitmq和Erlang、Mysql下载与配置

    1.快速搭建springboot框架(在idea中): file–>new project–>Spring Initializr–>next–>然后一直下一步. 然后复制一下代 ...

  5. springmvc SSM shiro redis 后台框架 多数据源 代码生成器

    A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址    ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...

  6. 集成ssm+shiro出现的 问题

    1.springmvc-servlet.xml .applicationContext.xml该如何配置include和exclude?,目前的做法是将.applicationContext.xml全 ...

  7. SSM+shiro,所有配置文件,详细注释版,自用

    spring配置文件applicationContext.xml,放在resources下 <?xml version="1.0" encoding="UTF-8& ...

  8. 学生会管理系统(SSM)vue+ssm+shiro

    数据库 drop database StudentUnionManagementSystem ; create database StudentUnionManagementSystem CHARAC ...

  9. Shiro第六篇【验证码、记住我】

    验证码 在登陆的时候,我们一般都设置有验证码,但是我们如果使用Shiro的话,那么Shiro默认的是使用FormAuthenticationFilter进行表单认证. 而我们的验证校验的功能应该加在F ...

随机推荐

  1. 清北考前刷题day4下午好

    /* 辗转相除,每次计算多出现了几个数. */ #include<iostream> #include<cstdio> #include<cstring> #inc ...

  2. bzoj4987: Tree(树形dp)

    Description 从前有棵树. 找出K个点A1,A2,…,Ak. 使得∑dis(AiAi+1),(1<=i<=K-1)最小.   Input 第一行两个正整数n,k,表示数的顶点数和 ...

  3. mysql百万数据分页查询速度

    百万数据测试 ,; 受影响的行: 时间: .080ms ,; 受影响的行: 时间: .291ms ,; 受影响的行: 时间: .557ms ,; 受影响的行: 时间: .821ms ,; 受影响的行: ...

  4. 公司4:JrVue主题定制

    JrVue是我们基于element重新封装的一套组件库;  具体组件使用方法可以mnote->研发小组查看; 这里我们定制了一套主题色, 具体变动如下: 1.主题色变动: mfront有蓝.紫. ...

  5. Linux之线程相关命令及常用命令

    查进程 top命令:查看系统的资源状况.#top top -d 10     //指定系统更新进程的时间为10秒 ps:查看当前用户的活动进程.#ps -A ps命令查找与进程相关的PID号: ps ...

  6. 二分搜索 POJ 2456 Aggressive cows

    题目传送门 /* 二分搜索:搜索安排最近牛的距离不小于d */ #include <cstdio> #include <algorithm> #include <cmat ...

  7. Q - Euclid in Manhattan(欧几里德距离==曼哈顿距离?)

    Desciption Consider a set of n points in a 2-D plane with integer coordinates. There are various way ...

  8. ACM_发工资(简单贪心)

    发工资咯: Time Limit: 2000/1000ms (Java/Others) Problem Description: 作为广财大的老师,最盼望的日子就是每月的8号了,因为这一天是发工资的日 ...

  9. LeetCode 要记得一些小trick

    最近搞了几场编程比赛,面试题或者是LeetCode周赛.每次都不能做完,发现时间不够用. 看了别人的代码才知道,同样实现相同的功能,可能别人只需要用一个恰当的函数,就会比自己少些不少代码,争得了时间. ...

  10. Spring.Net学习笔记(3)-创建对象

    一.开发环境 编译器:VS2013 .Net版本:.net framework4.5 二.涉及程序集 Spring.Core.dll:1.3 Common.Logging 三.开发过程 1.项目结构 ...