ssm+freemark集成shiro
Posted Nightliar
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ssm+freemark集成shiro相关的知识,希望对你有一定的参考价值。
1.导入的jar包
<!-- shiro start -->
<!-- freemarker + shiro(标签) begin -->
<dependency>
<groupId>net.mingsoft</groupId>
<artifactId>shiro-freemarker-tags</artifactId>
<version>0.1</version>
</dependency>
<!-- freemarker + shiro(标签) end -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
</dependency>
<!-- shiro end -->
2.在web.xml中加入shiro filter
<!--Shiro过滤器-->
<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>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
此过滤器要放在第一个,且名称要与spring-shiro,xml中shiro filter一致
3.在freemarker中加入shiro标签
3.1新建一个FreeMarkerConfigExtend类继承FreeMarkerConfigurer,
package com.business.util;
import java.io.IOException;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import com.jagregory.shiro.freemarker.ShiroTags;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;
public class FreeMarkerConfigExtend extends FreeMarkerConfigurer {
@Override
public void afterPropertiesSet() throws IOException, TemplateException {
super.afterPropertiesSet();
Configuration cfg = this.getConfiguration();
cfg.setSharedVariable("shiro", new ShiroTags());//shiro标签
cfg.setNumberFormat("#");//防止页面输出数字,变成2,000
//可以添加很多自己的要传输到页面的[方法、对象、值]
/*
* 在controller层使用注解再加一层判断
* 注解 @RequiresPermissions("/delete")
*/
/*shiro标签*/
/**
1.游客
<@shiro.guest>
您当前是游客,<a href="javascript:void(0);" class="dropdown-toggle qqlogin" >登录</a>
</@shiro.guest>
2.user(已经登录,或者记住我登录)
<@shiro.user>
欢迎[<@shiro.principal/>]登录,<a href="/logout.shtml">退出</a>
</@shiro.user>
3.authenticated(已经认证,排除记住我登录的)
<@shiro.authenticated>
用户[<@shiro.principal/>]已身份验证通过
</@shiro.authenticated>
4.notAuthenticated(和authenticated相反)
<@shiro.notAuthenticated>
当前身份未认证(包括记住我登录的)
</@shiro.notAuthenticated>
5.principal标签(能够取到你在realm中保存的信息比如我存的是ShiroUser对象,取出其中urlSet属性)
<!--需要指定property-->
<@shiro.principal property="urlSet"/>
6.hasRole标签(判断是否拥有这个角色)
<@shiro.hasRole name="admin">
用户[<@shiro.principal/>]拥有角色admin<br/>
</@shiro.hasRole>
7.hasAnyRoles标签(判断是否拥有这些角色的其中一个)
<@shiro.hasAnyRoles name="admin,user,member">
用户[<@shiro.principal/>]拥有角色admin或user或member<br/>
</@shiro.hasAnyRoles>
8.lacksRole标签(判断是否不拥有这个角色)
<@shiro.lacksRole name="admin">
用户[<@shiro.principal/>]不拥有admin角色
</@shiro.lacksRole>
9.hasPermission标签(判断是否有拥有这个权限)
<@shiro.hasPermission name="user:add">
用户[<@shiro.principal/>]拥有user:add权限
</@shiro.hasPermission>
10.lacksPermission标签(判断是否没有这个权限)
<@shiro.lacksPermission name="user:add">
用户[<@shiro.principal/>]不拥有user:add权限
</@shiro.lacksPermission>
**/
}
}
3.2修改spring-mvc-servlet.xml中的freemarker配置
4.新建CustomCredentialsMatcher类继承shiro的SimpleCredentialsMatcher类,这个类作用是自定义密码验证
package com.business.shiro;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import com.business.util.MD5Util;
/**
* Description: 告诉shiro如何验证加密密码,通过SimpleCredentialsMatcher或HashedCredentialsMatcher
* @Author: zh
* @Create Date: 2017-5-9
*/
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
Object tokenCredentials = MD5Util.hmac_md5(String.valueOf(token.getPassword()));
Object accountCredentials = getCredentials(info);
//将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false
return equals(tokenCredentials, accountCredentials);
}
}
5.新建ShiroDbRealm类
package com.business.shiro;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
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.subject.SimplePrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.business.dao.UserDao;
import com.business.entity.Menu;
import com.business.entity.Role;
import com.business.entity.User;
import com.business.entity.UserRole;
import com.business.service.sysService.MenuService;
import com.business.service.sysService.RoleService;
import com.business.service.sysService.UserRoleService;
import com.business.service.sysService.UserService;
import com.business.util.SessionUtil;
import com.common.util.BizUtil;
import com.google.common.collect.Sets;
/**
* @description:shiro权限认证
* @author:zhanghao
* @date:2017/5/8 14:51
*/
public class ShiroDbRealm extends AuthorizingRealm {
private static final Logger LOGGER = Logger.getLogger(ShiroDbRealm.class);
@Autowired private UserService userService;
@Autowired private UserDao userDao;
@Autowired private RoleService roleService;
@Autowired private UserRoleService userRoleService;
@Autowired private MenuService menuService;
public ShiroDbRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
super(cacheManager, matcher);
}
/**
* Shiro登录认证(原理:用户提交 用户名和密码 --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ---- shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authcToken) throws AuthenticationException {
LOGGER.info("Shiro开始登录认证");
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
User user = userDao.getByName(token.getUsername());
// 账号不存在
if (user == null) {
return null;
}
// 账号未启用
if (user.getStatus() == 1) {
throw new DisabledAccountException();
}
//将用户信息保存在session中
SessionUtil.addSession(user);
UserRole userRole = userRoleService.getByUserId(user.getId());
Role role = roleService.getById(userRole.getRoleId());
// 读取用户的url和角色
Set<String> roles = Sets.newHashSet(role.getName());
List<Long> menuIds = BizUtil.stringToLongList(role.getMenu(), ",");
List<Menu> menuList = menuService.getListByIds(menuIds);
List<String> menuStr = BizUtil.extractToList(menuList, "url");
Set<String> urls = Sets.newHashSet(menuStr);
urls.remove("");
urls.remove(null);
ShiroUser shiroUser = new ShiroUser(user.getId(), user.getLoginName(), user.getUsername(), urls);
shiroUser.setRoles(roles);
// 认证缓存信息
return new SimpleAuthenticationInfo(shiroUser, user.getPassword().toCharArray(),getName());
}
/**
* Shiro权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(shiroUser.getRoles());
info.addStringPermissions(shiroUser.getUrlSet());
return info;
}
@Override
public void onLogout(PrincipalCollection principals) {
super.clearCachedAuthorizationInfo(principals);
ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
removeUserCache(shiroUser);
}
/**
* 清除用户缓存
* @param shiroUser
*/
public void removeUserCache(ShiroUser shiroUser){
removeUserCache(shiroUser.getLoginName());
}
/**
* 清除用户缓存
* @param loginName
*/
public void removeUserCache(String loginName){
SimplePrincipalCollection principals = new SimplePrincipalCollection();
principals.add(loginName, super.getName());
super.clearCachedAuthenticationInfo(principals);
}
@PostConstruct
public void initCredentialsMatcher() {
//该句作用是重写shiro的密码验证,让shiro用我自己的验证-->指向重写的CustomCredentialsMatcher
setCredentialsMatcher(new CustomCredentialsMatcher());
}
}
6.自定义shiroUser
package com.business.shiro;
import java.io.Serializable;
import java.util.Set;
/**
* @description:自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息
* @author:zhanghao
* @date:2017/5/9
*/
public class ShiroUser implements Serializable {
private static final long serialVersionUID = -1373760761780840081L;
private Long id;
private final String loginName;
private String name;
private Set<String> urlSet;
private Set<String> roles;
public ShiroUser(String loginName) {
this.loginName = loginName;
}
public ShiroUser(Long id, String loginName, String name, Set<String> urlSet) {
this.id = id;
this.loginName = loginName;
this.name = name;
this.urlSet = urlSet;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<String> getUrlSet() {
return urlSet;
}
public void setUrlSet(Set<String> urlSet) {
this.urlSet = urlSet;
}
public Set<String> getRoles() {
return roles;
}
public void setRoles(Set<String> roles) {
this.roles = roles;
}
public String getLoginName() {
return loginName;
}
/**
* 本函数输出将作为默认的<shiro:principal/>输出.
*/
@Override
public String toString() {
return loginName;
}
}
7.两个缓存类
package com.business.shiro.cache;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.shiro.cache.CacheException;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
/**
* 使用spring-cache作为shiro缓存
* @author L.cm
*
*/
@SuppressWarnings("unchecked")
public class ShiroSpringCache<K, V> implements org.apache.shiro.cache.Cache<K, V> {
private static final Logger logger = Logger.getLogger(ShiroSpringCache.class);
private final org.springframework.cache.Cache cache;
public ShiroSpringCache(Cache cache) {
if (cache == null) {
throw new IllegalArgumentException("Cache argument cannot be null.");
}
this.cache = cache;
}
@Override
public V get(K key) throws CacheException {
if (logger.isTraceEnabled()) {
logger.trace("Getting object from cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass());
}
ValueWrapper valueWrapper = cache.get(key);
if (valueWrapper == null) {
if (logger.isTraceEnabled()) {
logger.trace("Element for [" + key + "] is null.");
}
return null;
}
return (V) valueWrapper.get();
}
@Override
public V put(K key, V value) throws CacheException {
if (logger.isTraceEnabled()) {
logger.trace("Putting object in cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass());
}
V previous = get(key);
cache.put(key, value);
return previous;
}
@Override
public V remove(K key) throws CacheException {
if (logger.isTraceEnabled()) {
logger.trace("Removing object from cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass());
}
V previous = get(key);
cache.evict(key);
return previous;
}
@Override
public void clear() throws CacheException {
if (logger.isTraceEnabled()) {
logger.trace("Clearing all objects from cache [" + this.cache.getName() + "]");
}
cache.clear();
}
@Override
public int size() {
return 0;
}
@Override
public Set<K> keys() {
return Collections.emptySet();
}
@Override
public Collection<V> values() {
return Collections.emptySet();
}
@Override
public String toString() {
return "ShiroSpringCache [" + this.cache.getName() + "]";
}
}
package com.business.shiro.cache;
import org.apache.log4j.Logger;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.util.Destroyable;
/**
* 使用spring-cache作为shiro缓存
* 缓存管理器
* @author L.cm
*
*/
public class ShiroSpringCacheManager implements CacheManager, Destroyable {
private static final Logger logger = Logger.getLogger(ShiroSpringCacheManager.class);
private org.springframework.cache.CacheManager cacheManager;
public org.springframework.cache.CacheManager getCacheManager() {
return cacheManager;
}
public void setCacheManager(org.springframework.cache.CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
if (logger.isTraceEnabled()) {
logger.trace("Acquiring ShiroSpringCache instance named [" + name + "]");
}
org.springframework.cache.Cache cache = cacheManager.getCache(name);
return new ShiroSpringCache<K, V>(cache);
}
@Override
public void destroy() throws Exception {
cacheManager = null;
}
}
8.spring-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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="true">
<description>Shiro安全配置</description>
<!--安全管理器-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--设置自定义Realm-->
<property name="realm" ref="shiroDbRealm"/>
<!--将缓存管理器,交给安全管理器-->
<property name="cacheManager" ref="shiroSpringCacheManager"/>
<!-- 记住密码管理 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>
<!-- 項目自定义的Realm -->
<bean id="shiroDbRealm" class="com.business.shiro.ShiroDbRealm">
<constructor-arg index="0" name="cacheManager" ref="shiroSpringCacheManager"/>
<constructor-arg index="1" name="matcher" ref="credentialsMatcher"/>
<!-- 启用身份验证缓存,即缓存AuthenticationInfo信息,默认false -->
<property name="authenticationCachingEnabled" value="true"/>
<!-- 缓存AuthenticationInfo信息的缓存名称 -->
<property name="authenticationCacheName" value="authenticationCache"/>
<!-- 缓存AuthorizationInfo信息的缓存名称 -->
<property name="authorizationCacheName" value="authorizationCache"/>
</bean>
<!-- 记住密码Cookie -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe"/>
<property name="httpOnly" value="true"/>
<!-- 7天,采用spring el计算方便修改[细节决定成败]! -->
<property name="maxAge" value="#{7 * 24 * 60 * 60}"/>
</bean>
<!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<!-- Shiro Filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 安全管理器 -->
<property name="securityManager" ref="securityManager"/>
<!-- 默认的登陆访问url -->
<property name="loginUrl" value="/login"/>
<!-- 登陆成功后跳转的url -->
<property name="successUrl" value="/menu/index"/>
<!-- 没有权限跳转的url -->
<property name="unauthorizedUrl" value="/login"/>
<property name="filterChainDefinitions">
<value>
<!--
anon 不需要认证
authc 需要认证
user 验证通过或RememberMe登录的都可以
-->
/login = anon
/favicon.ico = anon
/static/** = anon
/** = user
</value>
</property>
</bean>
<!-- 用户授权信息Cache, 采用spring-cache, 具体请查看spring-ehcache.xml、spring-redis.xml -->
<bean id="shiroSpringCacheManager" class="com.business.shiro.cache.ShiroSpringCacheManager">
<property name="cacheManager" ref="cacheManager"/>
</bean>
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 设置全局会话超时时间 半小时 -->
<property name="globalSessionTimeout" value="#{30 * 60 * 1000}"/>
<!-- url上带sessionId 默认为true -->
<!-- <property name="sessionIdUrlRewritingEnabled" value="false"/> -->
<property name="sessionDAO" ref="sessionDAO"/>
</bean>
<!-- 会话DAO 用于会话的CRUD -->
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<!-- Session缓存名字,默认就是shiro-activeSessionCache -->
<property name="activeSessionsCacheName" value="activeSessionCache"/>
<property name="cacheManager" ref="shiroSpringCacheManager"/>
</bean>
<!-- 在方法中 注入 securityManager ,进行代理控制 -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
<!-- 自定义验证 -->
<bean id="credentialsMatcher" class="com.business.shiro.CustomCredentialsMatcher"></bean>
</beans>
9.如果要再controller层中加入注解判断,还需在spring-mvc-servlet.xml中加入
<!-- 启用shrio 控制器授权注解拦截方式 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- AOP式方法级权限检查 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true"/>
</bean>
10.缓存的两个xml文件ehcache.xml,spring-ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" dynamicConfig="false">
<diskStore path="java.io.tmpdir"/>
<cache name="authorizationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache>
<cache name="authenticationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache>
<cache name="activeSessionCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache>
<!-- 缓存半小时 -->
<cache name="halfHour"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
diskPersistent="false" />
<!-- 缓存一小时 -->
<cache name="hour"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="false"
diskPersistent="false" />
<!-- 缓存一天 -->
<cache name="oneDay"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="86400"
timeToLiveSeconds="86400"
overflowToDisk="false"
diskPersistent="false" />
<!--
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<defaultCache name="defaultCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
<?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:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- Spring提供的基于的Ehcache实现的缓存管理器 -->
<!-- 如果有多个ehcacheManager要在bean加上p:shared="true" -->
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:spring/ehcache.xml"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
<property name="transactionAware" value="true"/>
</bean>
<!-- cache注解,和spring-redis.xml中的只能使用一个 -->
<cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>
</beans>
11.applicationContext.xml导入配置文件
<import resource="classpath:spring/spring-shiro.xml" />
<import resource="classpath:spring/spring-ehcache.xml" />
12.LoginController控制层方法
package com.business.controller.system;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.business.controller.BaseController;
import com.business.service.sysService.UserService;
import com.business.util.SessionUtil;
import com.google.common.collect.Maps;
@Controller
public class LoginController extends BaseController {
@Resource
private UserService userService;
@RequestMapping(value = "/login",method=RequestMethod.GET)
public String login() {
return "login";
}
@RequestMapping(value = "/login",method=RequestMethod.POST)
public String login(RedirectAttributes attributes, String username, String password, @RequestParam(value = "online", defaultValue = "0") Integer rememberMe) {
Map<String, Object> map = Maps.newHashMap();
if (StringUtils.isBlank(username)) {
map.put("errorInfo", "用户名不能为空");
}
if (StringUtils.isBlank(password)) {
map.put("errorInfo", "密码不能为空");
}
Subject user = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, username+password);
// 设置记住密码
token.setRememberMe(1 == rememberMe);
try {
user.login(token);
return "redirect:/menu/index";
} catch (UnknownAccountException e) {
map.put("errorInfo", "账号不存在!");
attributes.addFlashAttribute("error", map);
return "redirect:/login";
} catch (DisabledAccountException e) {
map.put("errorInfo", "账号未启用!");
attributes.addFlashAttribute("error", map);
return "redirect:/login";
} catch (IncorrectCredentialsException e) {
map.put("errorInfo", "密码错误!");
attributes.addFlashAttribute("error", map);
return "redirect:/login";
} catch (Throwable e) {
map.put("errorInfo", "登录异常!");
attributes.addFlashAttribute("error", map);
return "redirect:/login";
}
}
@RequestMapping(value = "/logout")
public String logout() {
SessionUtil.removeSession();
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "redirect:/login";
}
}
12.如何在控制层使用注解,可以在baseController中加入总的异常处理
@ExceptionHandler
public String exception(HttpServletRequest request, Exception e) {
//对异常进行判断做相应的处理
if(e instanceof AuthorizationException){
return "redirect:/logout";
}
return null;
}
以上是关于ssm+freemark集成shiro的主要内容,如果未能解决你的问题,请参考以下文章
Shiro + SSM(框架) + Freemarker(jsp)
SSM+Redis+Shiro+Maven框架搭建及集成应用
java SSM框架 代码生成器 websocket即时通讯 shiro redis 后台框架源码
java SSM框架 代码生成器 websocket即时通讯 shiro redis 后台框架源码