在实际项目中,每一个用户角色登录进系统看到的菜单可能会不一样,这样就涉及到了用户权限的问题,Shiro也是目前常用的权限框架。
一、授权方式
shiro支持三种授权方式:
1、编程式(基本不用):通过写if/else授权代码块完成。
2、注解式:通过在执行的Java方法上防止相应的注解完成,没有权限将抛出相应的异常。
3、JSP标签:在JSP页面通过相应的标签完成。
二、默认拦截器
1、rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
2、port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。
3、perms:例子/admins/user/**=perms[user:add:*],perms参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
4、roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如/admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
5、anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
6、authc:例如/admins/user/**=authc表示需要认证才能使用,没有参数
7、authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
8、ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
9、user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
这些过滤器分为两组,一组是认证过滤器,一组是授权过滤器。其中anon,authcBasic,auchc,user是第一组,
perms,roles,ssl,rest,port是第二组。
三、Shiro标签
使用shiro标签之前要在jsp中引入标签库
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
shiro的几种标签:
shiro:guest:用户没有身份验证时显示的信息 ,即游客访问信息
shiro:user:用户登陆后显示的信息,通过RememberMe认证通过
shiro:principal:显示用户身份信息
shiro:authenticated:用户已经身份验证通过,即通过Subject.login登录成功,不是RememberMe登录的
shiro:notAuthenticated:用户未进行身份验证,即没有通过Subject.login登录,包括RememberMe自动登录的也属于未进行身份验证
shiro:hasRole name="admin":如果当前Subject有角色,将显示body体内容
shiro:hasAnyRoles name="admin,user":只要有body体内有任意一个角色,就会显示里面的内容
shiro:lacksRole name="admin":如果当前的Subject没有角色将显示标签内内容
shiro:hasPermission name="user:create":如果当前Subject有权限就显示标签里的内容
shiro:lacksPermission name="org:create":如果当前Subject没有权限将显示标签里的内容
四、权限注解
权限注解可以用在service和controller层
1、@RequiresAuthentication:表示当前Subject已经通过login进行了身份验证;即Subject.isAuthenticated()返回true
2、@RequiresUser:表示当前Subject已经身份验证或者通过RemmberMe登录的
3、@RequiresGuest:表示当前Subject没有身份验证或通过RemmberMe登录过,即游客身份
4、@RequiresRole(value={"admin","user"},logical=Logical.AND):表示当前Subject需要角色admin和Uuser
5、RequiresPermissions(value={"user:a","user:b"},logical=Logical.OR):表示当前Subject需要权限user:a或user:b
五、具体实现
1、在web.xml中配置Spring、springmvc、shiro。
<?xml version="1.0" encoding="UTF-8"?>
<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">
<display-name>shiro-2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 1、配置Spring环境 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 2、配置SpringMVC环境 -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--
3、配置shiro 的 shiroFilter
DelegatingFilterProxy实际上是Filter的一个代理对象,默认情况下。
Spring会到IOC容器中查找和<filter-name>相应的filter bean。
也可以通过targetBeanName的初始化参数来配置filter 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>
</web-app>
2、配置springmvc配置文件:spring-servlet.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:p="http://www.springframework.org/schema/p"
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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 1、配置springmvc注解扫描 -->
<context:component-scan base-package="com.mfc"></context:component-scan>
<!-- 2、启用springmvc注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:default-servlet-handler/>
<!-- 3、 配置springmvc访问前后缀 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
3、配置IOC容器: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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!--
1、配置securityManager
-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<property name="authenticator" ref="authenticator"/>
<property name="realms">
<list>
<ref bean="jdbcRealm"/>
<ref bean="secondRealm"/>
</list>
</property>
<?xml version="1.0" encoding="UTF-8"?>
<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-4.0.xsd">
<!--
1、配置securityManager
-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<property name="authenticator" ref="authenticator"/>
<property name="realms">
<list>
<ref bean="jdbcRealm"/>
<ref bean="secondRealm"/>
</list>
</property>
<!-- 设置RemmberMe失效时间,注意这一句代码是后来加的,在下载的资源里面没有 -->
<property name="rememberMeManager.cookie.maxAge" value="10"></property>
</bean>
<!--
2、配置cacheManager
2.1、需要加入ehcache的jar包及配置文件
-->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean>
<!--
3、配置Realm
3.1、直接配置实现了org.apache.shiro.realm.Realm接口的bean
-->
<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<!--
配置认证策略 :
"FirstSuccessfulStrategy":只要有一个Realm验证成功即可,其他Realm忽略,只返回第一个验证陈宫的Realm身份验证成功的认证信息
"AtLeastOneSuccessfulStrategy":只要有一个Realm验证成功即可,返回所有Realm身份验证成功的认证信息
"AllSuccessfulStrategy":所有的Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败了就算是失败了
-->
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean>
</property>
</bean>
<bean id="jdbcRealm" class="com.mfc.realm.ShiroRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean>
<bean id="secondRealm" class="com.mfc.realm.SecondRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="SHA1"></property>
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean>
<!--
4、配置lifecycleBeanPostProcessor,可以自动的来调用配置在Spring IOC 容器中的shiro bean的生命周期方法
-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!--
5、启用IOC容器中使用shiro的注解。但必须在配置了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>
<!--
6、配置shiroFilter
6.1、id必须和web.xml中的配置的DelegatingFilterProxy的<filter-name>的值一致
若不一致会抛出异常NoSuchBeanDefinitionException。因为shiro会来IOC容器中查找和<filter-name>名字对应的filter bean
-->
<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="/list.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!-- 可以从数据表中初始化资源和权限,代替下面使用 filterChainDefinitions写死的权限配置-->
<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>
<!--
URL匹配模式:
?:匹配一个字符。如/admin将匹配/admin1,但不匹配/admin或/admin/
*:匹配0个或多个字符串。如/admin*将匹配/admin、/admin123,但不匹配/admin/1
**:匹配路径中的零个或多个路径。如/admin/**将匹配/admin/a或admin/a/b
配置哪些页面需要受保护,以及访问这些页面需要的权限,这里的URL权限采取第一次匹配优先的方式
1、anon 可以被匿名访问
2、authc 必须认证(即登录)后才可以访问的页面
3、logout 注销
4、roles 角色过滤器
-->
<!--
<property name="filterChainDefinitions">
<value>
/login.jsp = anon
/shiroCtrl/login = anon
/shiroCtrl/logout = logout
/user.jsp = roles[user]
/admin.jsp = roles[admin]
# everything else requires authentication:
/** = authc
</value>
</property>
-->
</bean>
<!--配置一个bean,该bean实际上是一个map,通过实例工厂方法的方式 -->
<bean id="filterChainDefinitionMap"
factory-bean="filterChainDefinitionMapBuilder"
factory-method="buildFilterChainDefinitionMapBuilder"></bean>
<bean id="filterChainDefinitionMapBuilder"
class="com.mfc.factory.FilterChainDefinitionMapBuilder"></bean>
<!-- 注入测试注解配置权限的service -->
<bean id="shiroService" class="com.mfc.service.ShiroService"></bean>
</beans>
</bean>
<!--
2、配置cacheManager
2.1、需要加入ehcache的jar包及配置文件
-->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean>
<!--
3、配置Realm
3.1、直接配置实现了org.apache.shiro.realm.Realm接口的bean
-->
<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<!--
配置认证策略 :
"FirstSuccessfulStrategy":只要有一个Realm验证成功即可,其他Realm忽略,只返回第一个验证陈宫的Realm身份验证成功的认证信息
"AtLeastOneSuccessfulStrategy":只要有一个Realm验证成功即可,返回所有Realm身份验证成功的认证信息
"AllSuccessfulStrategy":所有的Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败了就算是失败了
-->
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean>
</property>
</bean>
<bean id="jdbcRealm" class="com.mfc.realm.ShiroRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"></property>
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean>
<bean id="secondRealm" class="com.mfc.realm.SecondRealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="SHA1"></property>
<property name="hashIterations" value="1024"></property>
</bean>
</property>
</bean>
<!--
4、配置lifecycleBeanPostProcessor,可以自动的来调用配置在Spring IOC 容器中的shiro bean的生命周期方法
-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!--
5、启用IOC容器中使用shiro的注解。但必须在配置了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>
<!--
6、配置shiroFilter
6.1、id必须和web.xml中的配置的DelegatingFilterProxy的<filter-name>的值一致
若不一致会抛出异常NoSuchBeanDefinitionException。因为shiro会来IOC容器中查找和<filter-name>名字对应的filter bean
-->
<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="/list.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!-- 可以从数据表中初始化资源和权限,代替下面使用 filterChainDefinitions写死的权限配置-->
<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>
<!--
URL匹配模式:
?:匹配一个字符。如/admin将匹配/admin1,但不匹配/admin或/admin/
*:匹配0个或多个字符串。如/admin*将匹配/admin、/admin123,但不匹配/admin/1
**:匹配路径中的零个或多个路径。如/admin/**将匹配/admin/a或admin/a/b
配置哪些页面需要受保护,以及访问这些页面需要的权限,这里的URL权限采取第一次匹配优先的方式
1、anon 可以被匿名访问
2、authc 必须认证(即登录)后才可以访问的页面
3、logout 注销
4、roles 角色过滤器
-->
<!--
<property name="filterChainDefinitions">
<value>
/login.jsp = anon
/shiroCtrl/login = anon
/shiroCtrl/logout = logout
/user.jsp = roles[user]
/admin.jsp = roles[admin]
# everything else requires authentication:
/** = authc
</value>
</property>
-->
</bean>
<!--配置一个bean,该bean实际上是一个map,通过实例工厂方法的方式 -->
<bean id="filterChainDefinitionMap"
factory-bean="filterChainDefinitionMapBuilder"
factory-method="buildFilterChainDefinitionMapBuilder"></bean>
<bean id="filterChainDefinitionMapBuilder"
class="com.mfc.factory.FilterChainDefinitionMapBuilder"></bean>
<!-- 注入测试注解配置权限的service -->
<bean id="shiroService" class="com.mfc.service.ShiroService"></bean>
</beans>
4、创建Realm并要在Spring IOC容器中配置,这里会用了两个Realm,当然可以使用更多个。Realm认证策略参照:Shiro——认证
package com.mfc.realm;
import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
/**
* @author 74790
* 1.授权需要继承AuthorizingRealm,并实现doGetAuthorizationInfo 方法
2.AuthorizingRealm类继承自AuthenticatingRealm,但没有实现AuthenticatingRealm中的
doGetAuthenticationInfo,所以认证和授权只需要继承AuthorizingRealm就可以了,同时实现他的
两个抽象方法。
*/
public class ShiroRealm extends AuthorizingRealm {
// 认证的方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("[ShiroRealm] doGetAuthenticationInfo");
//1、把AuthenticationToken转化为UsernamePasswordToken
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
//2、UsernamePasswordToken中获取Username
String username = upToken.getUsername();
//3、调用数据库方法,从数据库中查询username对用的用户记录
System.out.println("从数据库中获取username:" + username + " 所对应的用户信息");
//4、若用户不存在,可以抛出UnknownAccountException异常
if("unknown".equals(username)){
throw new UnknownAccountException("用户不存在");
}
//5、根据用户信息的情况,决定是否需要抛出其他AuthenticationException异常
if("monster".equals(username)){
throw new LockedAccountException("用户被锁定");
}
//6、根据用户的情况来构建AuthenticationInfo对象并返回,通常使用的实现类是SimpleAuthenticationInfo
//以下信息是从数据库中获取的
//principal:认证的实体信息,可以是username,也可以是数据表对应的用户的实体类对象
Object principal = username;
//credentials:密码
Object credentials = null;
if("admin".equals(username)){
credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
}else if("user".equals(username)){
credentials = "098d2c478e9c11555ce2823231e02ec1";
}
//realmName:当前realm 对象的name,调用父类的getName()方法即可
String realmName = getName();
//盐值,防止两用户密码一样的时候不安全
ByteSource credentialsSalt = ByteSource.Util.bytes(username);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
return info;
}
// 授权需要实现的方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//1.从PrincipalCollection中获取登陆用户的信息
Object principal = principals.getPrimaryPrincipal();
//2.利用登陆用户的信息来获取当前用户的角色和权限(可能需要查询数据库)
Set<String> roles = new HashSet<String>();
roles.add("user");
if("admin".equals(principal)){
roles.add("admin");
}
//3.创建SimpleAuthorizationInfo对象,并设置其roles
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
//4.返回SimpleAuthorizationInfo对象
return info;
}
public static void main(String[] args) {
String hashIterations = "MD5";
Object credentials = "123456";
Object salt = ByteSource.Util.bytes("user");;
int algorithmName = 1024;
Object result = new SimpleHash(hashIterations, credentials, salt, algorithmName);
System.out.println("result:" + result);
}
}
package com.mfc.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;
/**
* @author 74790
* 认证的Realm
*/
public class SecondRealm extends AuthenticatingRealm {
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("[SecondRealm] doGetAuthenticationInfo");
//1、把AuthenticationToken转化为UsernamePasswordToken
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
//2、UsernamePasswordToken中获取Username
String username = upToken.getUsername();
//3、调用数据库方法,从数据库中查询username对用的用户记录
System.out.println("从数据库中获取username:" + username + " 所对应的用户信息");
//4、若用户不存在,可以抛出UnknownAccountException异常
if("unknown".equals(username)){
throw new UnknownAccountException("用户不存在");
}
//5、根据用户信息的情况,决定是否需要抛出其他AuthenticationException异常
if("monster".equals(username)){
throw new LockedAccountException("用户被锁定");
}
//6、根据用户的情况来构建AuthenticationInfo对象并返回,通常使用的实现类是SimpleAuthenticationInfo
//以下信息是从数据库中获取的
//principal:认证的实体信息,可以是username,也可以是数据表对应的用户的实体类对象
Object principal = username;
//credentials:密码
//Object credentials = "fc1709d0a95a6be30bc5926fdb7f22f4";
Object credentials = null;
if("admin".equals(username)){
credentials = "ce2f6417c7e1d32c1d81a797ee0b499f87c5de06";
}else if("user".equals(username)){
credentials = "073d4c3ae812935f23cb3f2a71943f49e082a718";
}
//realmName:当前realm 对象的name,调用父类的getName()方法即可
String realmName = getName();
//SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);
//盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(username);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
return info;
}
public static void main(String[] args) {
String hashIterations = "SHA1";
Object credentials = "123456";
Object salt = ByteSource.Util.bytes("admin");;
int algorithmName = 1024;
Object result = new SimpleHash(hashIterations, credentials, salt, algorithmName);
System.out.println("result:" + result);
}
}
5、测试注解配置权限的service:关于注解的使用可以看上面的四
package com.mfc.service;
import java.util.Date;
import org.apache.shiro.authz.annotation.RequiresRoles;
/**
* @author 74790
* Shiro的注解方式配置在service或者是Controller中
*/
public class ShiroService {
/*
* 只有admin角色才可以访问这个方法
* */
@RequiresRoles({"admin"})
public void test(){
System.out.println("ShiroService测试权限:" + new Date());
}
}
6、Controller:
package com.mfc.ctrl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.mfc.service.ShiroService;
@Controller
@RequestMapping(value = "shiroCtrl")
public class ShiroCtrl {
@Autowired
private ShiroService shiroService;
@RequestMapping(value = "test")
public String test(){
shiroService.test();
return "redirect:/list.jsp";
}
@RequestMapping(value = "login")
public String login(@RequestParam("username")String username,
@RequestParam("password")String password, Model model){
Subject currentUser = SecurityUtils.getSubject();
// 测试当前的用户是否已经被认证,即是否已经登录
// 调用Subject 的isAuthenticated()
if (!currentUser.isAuthenticated()) {
// 把用户名和密码封装为UsernamePasswordToken 对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// RememberMe
token.setRememberMe(true);
try {
// 执行登录
// 这里的token其实传到了ShiroRealm.doGetAuthenticationInfo(AuthenticationToken token)
currentUser.login(token);
}catch (AuthenticationException ae) {
// 所有认证时异常的父类
System.err.println("登录失败:"+ae.getMessage());
}
}
return "redirect:/list.jsp";
}
}
7、从数据库中获取权限配置资源的bean:这个bean需要在Spring IOC容器中注入,可以查看上面的applicationContext.xml配置文件。
package com.mfc.factory;
import java.util.LinkedHashMap;
/**
* @author 74790
* 使用bean配置的方式,将权限配置配置到数据库里面去
*/
public class FilterChainDefinitionMapBuilder {
public LinkedHashMap<String, String> buildFilterChainDefinitionMapBuilder(){
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
/*
*
这些可以存到数据库里面去,在这里取出来即可,注意放进map的顺序
/login.jsp = anon
/shiroCtrl/login = anon
/shiroCtrl/logout = logout
/user.jsp = roles[user]
/admin.jsp = roles[admin]
# everything else requires authentication:
/** = authc
* */
map.put("/login.jsp", "anon");
map.put("/shiroCtrl/login", "anon");
map.put("/shiroCtrl/logout", "logout");
map.put("/user.jsp", "roles[user]");
map.put("/admin.jsp", "roles[admin]");
map.put("/**", "authc");
return map;
}
}
8、JSP代码这里省略。