1.编写一个自定义权限类(继承AuthorizingRealm )
package com.zking.test.shiro;
import com.zking.test.biz.IUserBiz;
import com.zking.test.model.User;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import java.util.Set;
public class UserRealm extends AuthorizingRealm {
private static final Integer LOCKED = new Integer(1);
private IUserBiz userBiz;
public UserRealm() {
}
public UserRealm(CacheManager cacheManager) {
super(cacheManager);
}
public UserRealm(CredentialsMatcher matcher) {
super(matcher);
}
public UserRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
super(cacheManager, matcher);
}
public void setUserBiz(IUserBiz userBiz) {
this.userBiz = userBiz;
}
@Override
public String getName() {
return "UserRealm";
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username = (String) principalCollection.getPrimaryPrincipal();
User user = new User();
user.setUsername(username);
Set<String> permissions = userBiz.listPermissionsByUserName(user);
Set<String> roles = userBiz.listRolesByUserName(user);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(roles);
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username = (String) authenticationToken.getPrincipal();
User user = new User();
user.setUsername(username);
User u = userBiz.loadByUsername(user);
if (null == u) {
throw new UnknownAccountException();
}
if (LOCKED.equals(u.getLocked())) {
throw new LockedAccountException();
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
u.getUsername(),
u.getPassword(),
ByteSource.Util.bytes(u.getSalt()),
getName()
);
return authenticationInfo;
}
}
2 编写一个凭证匹配器类
package com.zking.test.shiro;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import java.util.concurrent.atomic.AtomicInteger;
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
private Cache<String, AtomicInteger> passwordRetryCache;
private String cacheName = "passwordRetryCache";
private CacheManager cacheManager;
public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
public void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
public void init() {
passwordRetryCache = cacheManager.getCache(this.cacheName);
}
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
String username = (String) token.getPrincipal();
AtomicInteger retryCount = passwordRetryCache.get(username);
if (retryCount == null) {
retryCount = new AtomicInteger(0);
passwordRetryCache.put(username, retryCount);
}
if (retryCount.incrementAndGet() > 5) {
throw new ExcessiveAttemptsException();
}
boolean match = super.doCredentialsMatch(token, info);
if (match) {
passwordRetryCache.remove(username);
}
return match;
}
}
3 shiro.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<description>apache shiro配置</description>
<!-- 缓存管理器:本章使用Ehcache实现,也可以换成redis等其它缓存技术 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean>
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher" class="com.zking.test.shiro.RetryLimitHashedCredentialsMatcher" init-method="init">
<!--使用有参数构造方法创建对象,注入缓存管理器-->
<constructor-arg ref="cacheManager"/>
<!--指定缓存对象的名字-->
<property name="cacheName" value="passwordRetryCache"/>
<!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
<!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
<!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
<!--以下三个配置告诉shiro将如何对用户传来的明文密码进行加密-->
<!--指定hash算法为MD5-->
<property name="hashAlgorithmName" value="md5"/>
<!--指定散列次数为1024次-->
<property name="hashIterations" value="1024"/>
<!--true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储-->
<property name="storedCredentialsHexEncoded" value="true"/>
</bean>
<!-- Realm实现 配置一个自定义权限类 -->
<bean id="userRealm" class="com.zking.test.shiro.UserRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
<property name="userBiz" ref="userBiz"/>
</bean>
<!-- 配置安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm"/>
</bean>
<!-- 配置Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!--访问需要认证的地址时,没有认证跳转的地址,默认跳网站首页,然后经springmvc转到/WEB-INF/jsp/login.jsp-->
<property name="loginUrl" value="/"/>
<!-- 登录后,没有访问权限将跳转的地址 -->
<property name="unauthorizedUrl" value="/user/unauthorized"/>
<property name="filterChainDefinitions">
<!-- **表示匹配0个或多个路径 ,*表示匹配0个或多个字符串,?表示匹配一个字符 -->
<!-权限列表-->
<value>
/css