权限管理实现对用户访问系统的控制 用户可以访问而且只能访问自己被授权的资源 只要有用户和密码的系统,权限管理几乎都会出现 举例 给张三赋予“人力资源经理”角色, “人力资源经理”具有“查询员工”、“添加员工”、“修改员工”和“删除员工”权限。 此时张三能够进入系统,则可以进行这些操作;
Apache Shiro是Java的一个安全框架 Shiro是一个强大的简单易用的Java安全框架,主要用来更便捷的认证、授权、加密、会话管理、与Web集成、缓存等 Shiro使用起来小而简单 spring中有spring security ,是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。 shiro不依赖于spring,shiro不仅可以实现web应用的权限管理,还可以实现c/s系统,分布式系统权限管理, shiro属于轻量框架,越来越多企业项目开始使用shiro.
整体类图
当前的操作用户 可以是人 爬虫 当前跟软件交互的东西 在shiro当中我们可以统称"用户" 在代码的任何地方,你都能轻易的获得Shiro Subject。 一旦获得Subject,你就可以立即获得你希望用Shiro为当前用户做的90%的事情:登录、退、访问会话、执行授权检查等
SecurityManager则管理所有用户的安全操作 引用了多个内部嵌套安全组件,是Shiro框架的核心 你可以把它看成DispatcherServlet前端控制器。 用于调度各种Shiro框架的服务
Realms则是用户的信息认证器和用户的权限认证器 执行认证(登录)和授权(访问控制)时,Shiro会从应用配置的Realm中查找很多内容 Realm 可以理解为读取用户信息、角色及权限的 DAO SecurityManager要验证用户身份与权限,那么它需要从Realm获取相应的信息进行比较以确定用户身份是否合法; 可以把Realm看成DataSource,即安全数据源。
整体架构图
什么是认证
身份认证,就是判断一个用户是否为合法用户的处理过程 通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确
关键对象
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
[users]
itlike=1234
my=1234
1.构建securityManager工厂 2.通过工厂创建securityManager 3.将securityManager设置到运行环境中 4.创建一个Subject实例 5.创建token令牌 6.用户登录 7.用户退出
/*1.构建securityManager工厂*/
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
/*2.通过工厂创建securityManager*/
SecurityManager securityManager = factory.getInstance();
/*3.将securityManager设置到运行环境中*/
SecurityUtils.setSecurityManager(securityManager);
/*4.创建一个Subject实例*/
Subject subject = SecurityUtils.getSubject();
/*5.创建token令牌 用户名和密码*/
UsernamePasswordToken token = new UsernamePasswordToken("itlike", "1234");
/*6.用户登陆*/
try {
subject.login(token);
} catch (UnknownAccountException e) {
System.out.println("用户名不存在");
e.printStackTrace();
}catch (IncorrectCredentialsException e){
System.out.println("密码错误");
e.printStackTrace();
}
System.out.println("是否认证"+subject.isAuthenticated());
/*7.用户退出*/
subject.logout();
System.out.println("是否认证"+subject.isAuthenticated());
认证代码执行流程
3.Authenticator的实现ModularRealmAuthenticator调用realm从ini配置文件取用户真实的账号和密码
myRealm=MyRealm
securityManager.realms=$myRealm
概述
散列算法一般用于生成数据的摘要信息,是一种不可逆的算法 一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等
使用shiro进行散列密码 Md5Hash SimpleHash
Md5Hash md5Hash = new Md5Hash("itlike");
System.out.println(md5Hash);
/*通过加盐的方式来对密码进一步保护*/
Md5Hash md5Hash2 = new Md5Hash("itlike","myxq");
System.out.println(md5Hash2);
/*可进行二次散列*/
Md5Hash md5Hash3 = new Md5Hash("itlike","myxq",2);
System.out.println(md5Hash3);
/*使用SimpleHash*/
SimpleHash simpleHash = new SimpleHash(
"md5",
"itlike",
"myxq",
2);
System.out.println(simpleHash);
realm中配置散列 在ini文件当中进行散列
[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=3
#指定realm
myRealm=com.itlike.MyRealm
#配置散列
myRealm.credentialsMatcher=$credentialsMatcher
#配置自定义散列
securityManager.realms=$myRealm
要保证数据库中的密码是经过散列之后的
什么是授权
授权,即访问控制,控制谁能访问哪些资源。 主体进行身份认证后需要分配权限,方可访问系统的资源,对于某些资源没有权限是无法访问的。
使用ini形式配置权限信息
在ini文件中用户、角色、权限的配置规则 用户名=密码,角色1,角色2… 首先根据用户名找角色,再根据角色找权限,角色是权限集合。
权限字符串的规则
“资源标识符:操作:资源实例标识符” 对哪个资源的哪个实例具有什么操作 :”是资源/操作/实例的分割符 权限字符串也可以使用*通配符 示例
[users]
#用户itlike的密码是1234,此用户具有role1和role2两个角色
itlike=1234,role1,role2
myxq=1234,role2
[roles]
#角色role1对资源user拥有create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#角色role3对资源user拥有create权限
role3=user:create
自定义Realm形式权限
/*获取身份信息*/
Object principal = principals.getPrimaryPrincipal();
/*根据用户名查询该用户的角色和权限*/
List<String> roles = new ArrayList();
roles.add("role1");
roles.add("role2");
List<String> permissions = new ArrayList();
permissions.add("user:create");
permissions.add("user:delete");
/*把角色和权限与subject关联在一起,返回*/
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permissions);
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.30</version>
<scope>test</scope>
</dependency>
public static void main( String[] args ){
/**
* 1.构建securityManager工厂
* 2.通过工厂创建securityManager
* 3.将securityManager设置到运行环境中
* 4.创建一个Subject实例
* 5.创建token令牌
* 6.用户登录
* 7.用户退出
*/
//1.构建securityManager工厂
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2.通过工厂创建securityManager
SecurityManager securityManager = factory.getInstance();
//3.将securityManager设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//4.创建一个Subject实例
Subject subject = SecurityUtils.getSubject();
//5.创建token令牌
UsernamePasswordToken token = new UsernamePasswordToken("joker", "1234");
// 6.用户登录
try {
subject.login(token);
}catch (UnknownAccountException e){
/*账号不存在*/
System.out.println("账号不存在");
}catch (IncorrectCredentialsException e){
/*密码错误*/
System.out.println("密码错误");
}
System.out.println("是否认证成功"+subject.isAuthenticated());
//7.用户退出
subject.logout();
System.out.println("是否认证成功"+subject.isAuthenticated());
}
自定义realm
/*认证AuthenticationInfo*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
/*判断用户名密码是否存在*/
/*获取用户名*/
String username=(String) token.getPrincipal();
/*从数据库中查询密码*/
String name="joker";
String password="1234";
if(!name.equals(username)){
return null;
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, this.getName());
return info;
}
myRealm=com.dj.myRealm
securityManager.realms=$myRealm
散列密码加盐 配置散列信息
4. 授权 在 shiro-permission.ini配置文件配置
[users]
#用户itlike的密码是1234,此用户具有role1和role2两个角色
itlike=1234,role1,role2
myxq=1234,role2
[roles]
#角色role1对资源user拥有create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#角色role3对资源user拥有create权限
role3=user:create
System.out.println("是否认证成功"+subject.isAuthenticated());
//在认证成功之后才去授权
//判断当前用户是否有某个角色和
System.out.println(subject.hasRole("role1"));
/*判断当前用户是否有多个角色*/
System.out.println(subject.hasAllRoles(Arrays.asList("role1", "role2")));
/*判断使用有某个权限*/
System.out.println(subject.isPermitted("user:update"));
/*判断是否具备多个权限*/
System.out.println(subject.isPermittedAll("user:create", "user:delete"));
自定义Realm形式权限
/*授权AuthorizationInfo*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
/*获取身份信息*/
Object principal = principals.getPrimaryPrincipal();
/*根据用户名查询该用户的角色和权限*/ //从数据库查
List<String> roles = new ArrayList();
roles.add("role1");
roles.add("role2");
List<String> permissions = new ArrayList();
permissions.add("user:create");
permissions.add("user:delete");
/*把角色和权限与subject关联在一起,返回*/
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permissions);
return info;
}
<dependencies>
<!--Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!--Servlet - JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.6</version>
</dependency>
<!--shiro-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<!-- 拦截到所有请求,使用spring一个bean来进行处理 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!-- 是否filter中的init和 destroy-->
<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>
web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="false">
<absolute-ordering/>
<display-name>web</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--配置前端控制器-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!--加载的主配置文件-->
<param-value>classpath*:applicationContext.xml</param-value>
</init-param>
<!-- 项目启动就加载框架 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 拦截到所有请求,使用spring一个bean来进行处理 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!-- 是否filter中的init和 destroy-->
<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>
</web-app>
application-mvc.xml
<?xml version="1.0" encoding="UTF-8" ?>
<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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
">
<mvc:annotation-driven />
<!--静态资源处理 -->
<mvc:default-servlet-handler/>
<!--视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp" />
</bean>
</beans>
application-mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--spring-Mybatis整合-->
<!--加载数据库属性文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<!--属性文件当中的名称不能和name名称一样-->
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Mybatis的工厂 -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 核心配置文件的位置 -->
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
<!--配置mapper映射文件的路径-->
<property name="mapperLocations" value="classpath*:com/dj/mapper/*mapper.xml"/>
</bean>
<!-- 配置Mapper接口扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 配置Mapper扫描包 -->
<property name="basePackage" value="com.dj.mapper" />
</bean>
</beans>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--注解扫描-->
<context:component-scan base-package="com.dj"/>
<!--导入mybatis-->
<import resource="classpath:application-mybatis.xml"/>
<!--导入springMVC-->
<import resource="classpath:application-mvc.xml"/>
<!--导入shiro-->
<import resource="classpath:application-shiro.xml"/>
</beans>
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/permission?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>-->
<typeAliases>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
<package name="com.dj.domain" />
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugin>
</plugins>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<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" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--表单过滤器-->
<bean id="MyFormFilter" class="com.dj.web.filter.MyFormFilter"></bean>
<!-- 配置shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
<!-- 配置登录认证的路径 -->
<property name="loginUrl" value="/login" />
<!--配置表单监听过滤器-->
<property name="filters">
<map>
<entry key="authc" value-ref="MyFormFilter"/>
</map>
</property>
<!-- 配置shiro过滤器pattern -->
<property name="filterChainDefinitions">
<value>
/static/** = anon <!--不需要登录验证-->
/login.jsp = anon <!--不需要登录验证-->
/logout=logout <!--取消认证-->
/**=authc <!--除指定请求外,其它所有的请求都需要身份验证-->
</value>
</property>
</bean>
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 散列算法 -->
<property name="hashAlgorithmName" value="md5"/>
<!-- 散列次数 -->
<property name="hashIterations" value="2"></property>
</bean>
<!--自定义realm-->
<bean id="employeeRealm" class="com.dj.web.realm.EmplyeeRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<!-- 配置shiro安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--注入realm-->
<property name="realm" ref="employeeRealm"></property>
<property name="cacheManager" ref="ehCache"/>
</bean>
<!-- <aop:config proxy-target-class="true">-->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<!-- 缓存管理器 -->
<bean id="ehCache" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
</bean>
</beans>
<!-- 配置登录认证的路径 -->
<property name="loginUrl" value="/login" />
5. 创建自定义realm
/*认证*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("来到了认证");
String username=(String)token.getPrincipal();
System.out.println(username);
/*到数据中查询有没有当前用户*/
employee employee = service.getEmployeeWithUsername(username);
System.out.println(employee);
if(employee==null){
return null;
}
/*认证*/
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(employee,employee.getPassword(),this.getName());
return info;
public class MyFormFilter extends FormAuthenticationFilter {
/*认证成功会调用*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
response.setCharacterEncoding("UTF-8");
/*响应给浏览器*/
System.out.println("认证成功");
AjaxRes ajaxRes = new AjaxRes(true, "登录成功");
/*把对象转成json字符串*/
String jsonString = new ObjectMapper().writeValueAsString(ajaxRes);
response.getWriter().print(jsonString);
return false;
}
/*认证失败 会调用*/
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
/*响应给浏览器*/
System.out.println("认证失败");
return false;
}
}
/*认证失败 会调用*/
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
/*响应给浏览器*/
response.setCharacterEncoding("UTF-8");
if(e!=null){
/*获取异常名称*/
String name = e.getClass().getName();
AjaxRes ajaxRes=null;
if(name.equals(UnknownAccountException.class.getName())){
/*账号不存在*/
ajaxRes = new AjaxRes(false, "账号不存在");
}else if(name.equals(IncorrectCredentialsException.class.getName())){
/*密码错误*/
ajaxRes = new AjaxRes(false, "密码错误");
}else {
/*未知异常*/
ajaxRes = new AjaxRes(false, "未知异常");
}
String jsonString = null;
try {
jsonString = new ObjectMapper().writeValueAsString(ajaxRes);
response.getWriter().print(jsonString);
} catch (IOException ex) {
ex.printStackTrace();
}
}
return false;
}
11. 设置注销url
12. 授权注解
配置支持shiro注解
<!--
配置为true即使用cglib继承的方式,
false为jdk的接口动态代理 控制器没有实现接口
-->
<aop:config proxy-target-class="true" ></aop:config>
<!-- 使用第三方去扫描shiro的注解 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor ">
<property name="securityManager" ref="securityManager"></property>
</bean>
/*授权*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
System.out.println("来到了授权");
employee employee = (employee)principal.getPrimaryPrincipal();
List<String> roles=service.getroleById(employee.getId());
List<String> permission=service.getpermission(employee.getId());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permission);
return info;
}
<shiro:hasPermission name=""></shiro:hasPermission>
<shiro:hasRole name=""></shiro:hasRole>
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 散列算法 -->
<property name="hashAlgorithmName" value="md5"/>
<!-- 散列次数 -->
<property name="hashIterations" value="2"></property>
</bean>
<!--自定义realm-->
<bean id="employeeRealm" class="com.dj.web.realm.EmplyeeRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
shiro.xml
17. 菜单权限
/*获取树形菜单数据*/
@RequestMapping("/getTreeData")
@ResponseBody
public List<menu> getTreeData(){
List<menu> treeData = service.getTreeData();
System.out.println(treeData);
/*判断权限
如果没有就移除
* */
/*获取用户*/
Subject subject = SecurityUtils.getSubject();
/*当前用户*/
employee employee =(employee) subject.getPrincipal();
if(!employee.getAdmin()){
/*不是管理员 校验权限*/
chePermission(treeData);
}
return treeData;
}
/*校验权限*/
public void chePermission(List<menu> menus){
Subject subject = SecurityUtils.getSubject();
/*遍历所有菜单 及子菜单*/
Iterator<menu> iterator = menus.iterator();
while (iterator.hasNext()) {
menu m = iterator.next();
if(m.getPermission()!=null){
/*判断当前菜单是否有权限 没有就移除*/
String presources = m.getPermission().getPresources();
if(!subject.isPermitted(presources)){
/*没有 从菜单集合 移除*/
iterator.remove();
continue;
}
}
/*判断是否有子菜单 如果有 继续做校验*/
if(m.getChildren().size()>0){
chePermission(m.getChildren());
}
}
}