耀眼的橘子
2017-04-18 14:20:45
apache shiro安全框架 登录,记住我,前后台分离
最近做的项目,由于客户需求,登录的用户信息必须经过身份验证,自己研究了一下,写个博客与大家分享一下我的心得。本次项目用到了shiro的登录,记住我,前后台分离功能。这里只做了登录认证,没有权限管理。
项目构建:
在pom.xml文件:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3 </version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.3 </version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.3 </version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-cas</artifactId> <version>1.2.3 </version> </dependency>
在 web.xml文件里:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml,classpath:shiro/spring-context-shiro.xml</param-value> </context-param> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
shrio配置文件 spring-context-shiro:
<?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" 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" default-lazy-init="true"> <description>Shiro Configuration</description> <!--多个realm 的集中管理 --> <bean id="defineModularRealmAuthenticator" class="包路径.DefautModularRealm"> <property name="definedRealms"> <map> <entry key="systemAuthorizingRealm" value-ref="systemAuthorizingRealm" /> <entry key="userAuthorizingRealm" value-ref="userAuthorizingRealm" /> </map> </property> <!-- <property name="authenticationStrategy"> <bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy" /> </property> --> </bean> <!-- Shiro权限过滤过滤器定义 --> <bean name="shiroFilterChainDefinitions" class="java.lang.String"> <constructor-arg> <value> /userMember/login = authc /logout = logout /apply/** = user /alter/** = user </value> </constructor-arg> </bean> <!-- 安全认证过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/userMember/login" /> <property name="successUrl" value="/home/forward" /> <property name="filters"> <map> <entry key="cas" value-ref="casFilter" /> <entry key="authc" value-ref="formAuthenticationFilter" /> <entry key="logout" value-ref="logoutFilter" /> </map> </property> <property name="filterChainDefinitions"> <ref bean="shiroFilterChainDefinitions" /> </property> </bean> <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="/home/forward" /> </bean> <bean id="casFilter" class="org.apache.shiro.cas.CasFilter"> <!--配置验证错误时的失败页面 /main 为系统登录页面 --> <property name="failureUrl" value="/message.jsp" /> </bean> <!-- 基于Form表单的身份验证过滤器 --> <bean id="formAuthenticationFilter" class="包路径.FormAuthenticationFilter"> <property name="usernameParam" value="name" /> <property name="passwordParam" value="password" /> <property name="logintypeParam" value="logintype" /> <property name="loginUrl" value="/login.jsp" /> <property name="rememberMeParam" value="rememberMe"/> </bean> <!-- 定义Shiro安全管理配置 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="authenticator" ref="defineModularRealmAuthenticator" /> <!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 --> <!-- <property name="realm" ref="loginRealm"/> --> <property name="realms" > <list> <bean id="systemAuthorizingRealm" class="包路径.SystemAuthorizingRealm" /> <bean id="userAuthorizingRealm" class="包路径.UserAuthorizingRealm" /> </list> </property> <!-- <property name="sessionManager" ref="sessionManager" /> --> <property name="cacheManager" ref="memoryConstrainedCacheManager" /> <property name="rememberMeManager" ref="rememberMeManager"/> </bean> <bean id="systemAuthorizingRealm" class="包路径.SystemAuthorizingRealm"> </bean> <bean id="userAuthorizingRealm" class="包路径.UserAuthorizingRealm"> </bean> <!-- 定义授权缓存管理器 --> <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManager" ref="cacheManager" /> </bean> <bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> <!-- 自定义会话管理配置 --> <!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID, 当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="sessionDAO" ref="sessionDAO" /> <!-- 会话超时时间,单位:毫秒 --> <property name="globalSessionTimeout" value="${session.sessionTimeout}" /> <!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话 --> <property name="sessionValidationInterval" value="${session.sessionTimeoutClean}" /> <!-- <property name="sessionValidationSchedulerEnabled" value="false"/> --> <property name="sessionValidationSchedulerEnabled" value="true" /> <property name="sessionIdCookie" ref="sessionIdCookie" /> <property name="sessionIdCookieEnabled" value="true" /> </bean> <!-- 会话Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg name="name" value="applyid" /> <property name="httpOnly" value="true"/> <property name="maxAge" value="-1"/> </bean> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="604800"/><!-- 7天 --> </bean> <!-- rememberMe管理器 --> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/> <property name="cookie" ref="rememberMeCookie"/> </bean> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <!-- <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/> --> <property name="cacheManager" ref="shiroCacheManager" /> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> </beans>
在这里有一个 logintype,这个变量是我,是我自定义的,本身的shrio是没有,是做前后台登录的标志位。
FormAuthenticationFilter 类:
package 包路径; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.web.util.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter { /** * logger日志 */ protected Logger logger = LoggerFactory.getLogger(getClass()); /** * 序列化id */ private static final long serialVersionUID = -2271706136984114038L; /** * 登录类型 */ public static final String DEFAULT_LOGINTYPE_PARAM = "logintype"; private String logintypeParam = DEFAULT_LOGINTYPE_PARAM; protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); String logintype = getLogintype(request); logger.debug("createToken username:{},password:{},loginType:{"+logintype+"} ...",username,password); if (password==null){ password = ""; } String host = getRemoteAddr((HttpServletRequest)request); boolean rememberMe = isRememberMe(request); return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, logintype); } public void setLogintypeParam(String logintypeParam) { this.logintypeParam = logintypeParam; } public String getLogintypeParam() { return logintypeParam; } protected String getLogintype(ServletRequest request) { return WebUtils.getCleanParam(request, getLogintypeParam()); } /** * 获得用户远程地址 */ public static String getRemoteAddr(HttpServletRequest request){ String remoteAddr = request.getHeader("X-Real-IP"); if (StringUtils.isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("X-Forwarded-For"); }else if (StringUtils.isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("Proxy-Client-IP"); }else if (StringUtils.isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("WL-Proxy-Client-IP"); } return remoteAddr != null ? remoteAddr : request.getRemoteAddr(); } }
UsernamePasswordToken 类:
package 包路径; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken { /** * logger日志 */ protected Logger logger = LoggerFactory.getLogger(getClass()); /** * 序列化id */ private static final long serialVersionUID = -2271706136984114038L; /** * 登录类型 */ private String logintype ; public String getLogintype() { return logintype; } public void setLogintype(String logintype) { this.logintype = logintype; } public UsernamePasswordToken (String username, char[] password, boolean rememberMe, String host, String logintype) { super(username, password, rememberMe, host); this.logintype = logintype; } }
DefautModularRealm 类,多个realm集中管理:
package 包路径; import java.util.Collection; import java.util.Map; import org.apache.shiro.ShiroException; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.realm.Realm; import org.apache.shiro.util.CollectionUtils; import 系统文件路径.SysConstant; public class DefautModularRealm extends org.apache.shiro.authc.pam.ModularRealmAuthenticator{ private Map<String, Object> definedRealms; /** * 多个realm实现 */ @Override protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) { return super.doMultiRealmAuthentication(realms, token); } /** * 调用单个realm执行操作 */ @Override protected AuthenticationInfo doSingleRealmAuthentication(Realm realm,AuthenticationToken token) { // 如果该realms不支持(不能验证)当前token if (!realm.supports(token)) { throw new ShiroException("token错误!"); } AuthenticationInfo info = null; try { info = realm.getAuthenticationInfo(token); if (info == null) { throw new ShiroException("token不存在!"); } } catch (Exception e) { throw new ShiroException("用户名或者密码错误!"); } return info; } /** * 判断登录类型执行操作 */ @Override protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)throws AuthenticationException { this.assertRealmsConfigured(); Realm realm = null; UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; //判断是否是后台用户 if (token.getLogintype().equals(SysConstant.FRONT_LOGIN)) { realm = (Realm) this.definedRealms.get("systemAuthorizingRealm"); } else if (token.getLogintype().equals(SysConstant.ADMIN_LOGIN)){ realm = (Realm) this.definedRealms.get("userAuthorizingRealm"); } return this.doSingleRealmAuthentication(realm, authenticationToken); } /** * 判断realm是否为空 */ @Override protected void assertRealmsConfigured() throws IllegalStateException { this.definedRealms = this.getDefinedRealms(); if (CollectionUtils.isEmpty(this.definedRealms)) { throw new ShiroException("值传递错误!"); } } public Map<String, Object> getDefinedRealms() { return this.definedRealms; } public void setDefinedRealms(Map<String, Object> definedRealms) { this.definedRealms = definedRealms; } }
SystemAuthorizingRealm 后台认证realm
package 包路径; import javax.annotation.PostConstruct; import javax.annotation.Resource; 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.UnknownAccountException; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import 系统文件路径.ENUM_SYSTEM; import 系统文件路径.重写后台用户实体类.Principal; import 系统文件路径.后台用户实体类.UserMemberDO; import 系统文件路径.后台用户服务.UserMemberService; @Service public class SystemAuthorizingRealm extends AuthorizingRealm { /** * logger日志 */ protected Logger logger = LoggerFactory.getLogger(getClass()); /** * 序列化id */ private static final long serialVersionUID = -2271706136984114038L; /** * userMemberServicef服务 */ @Resource private UserMemberService userMemberService; /** * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission("sys:manager"); info.addStringPermission("user"); System.out.println("开始授权"); return info; } /** * 认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; UserMemberDO user = userMemberService.getByName(token.getUsername()); if (user == null ) { throw new UnknownAccountException("用户名不存在"); } else if (ENUM_SYSTEM.ACCOUNT_VERIFICATION_NO.getKey().equals(user.getStatus())) { throw new DisabledAccountException("账户未审核通过!"); } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(new Principal(user), user.getPassword(), null, getName()); return authenticationInfo; } /** * 设定密码校验的MD5算法与迭代次数 */ @PostConstruct public void initCredentialsMatcher() { HashedCredentialsMatcher matcher = new HashedCredentialsMatcher("MD5"); setCredentialsMatcher(matcher); } @Override protected void clearCachedAuthorizationInfo(PrincipalCollection principals) { super.clearCachedAuthorizationInfo(principals); } @Override protected void clearCachedAuthenticationInfo(PrincipalCollection principals) { super.clearCachedAuthenticationInfo(principals); } @Override protected void clearCache(PrincipalCollection principals) { super.clearCache(principals); } public void clearAllCachedAuthorizationInfo() { getAuthorizationCache().clear(); } public void clearAllCachedAuthenticationInfo() { getAuthenticationCache().clear(); } public void clearAllCache() { clearAllCachedAuthorizationInfo(); clearAllCachedAuthenticationInfo(); } }
UserAuthorizingRealm 前台用户认证realm
package 包路径.shiro; import javax.annotation.PostConstruct; import javax.annotation.Resource; 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.UnknownAccountException; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import 系统路径.ENUM_SYSTEM; import 系统路径.重写前台用户实体类.user.Principal; import 系统路径.前台用户实体类.user.UserDO; import 系统路径.前台用户服务.user.UserService; @Service public class UserAuthorizingRealm extends AuthorizingRealm { /** * logger日志 */ protected Logger logger = LoggerFactory.getLogger(getClass()); /** * 序列化id */ private static final long serialVersionUID = -2271706136984114038L; /** * userMemberServicef服务 */ @Resource private UserService userService; /** * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission("sys:manager"); info.addStringPermission("user"); System.out.println("开始授权"); return info; } /** * 认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; System.out.println(token.getUsername()); UserDO user = userService.getByName(token.getUsername()); if (user == null ) { throw new UnknownAccountException("用户名不存在"); } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(new Principal(user), user.getPassword(), null, getName()); return authenticationInfo; } /** * 设定密码校验的MD5算法与迭代次数 */ @PostConstruct public void initCredentialsMatcher() { HashedCredentialsMatcher matcher = new HashedCredentialsMatcher("MD5"); setCredentialsMatcher(matcher); } @Override protected void clearCachedAuthorizationInfo(PrincipalCollection principals) { super.clearCachedAuthorizationInfo(principals); } @Override protected void clearCachedAuthenticationInfo(PrincipalCollection principals) { super.clearCachedAuthenticationInfo(principals); } @Override protected void clearCache(PrincipalCollection principals) { super.clearCache(principals); } public void clearAllCachedAuthorizationInfo() { getAuthorizationCache().clear(); } public void clearAllCachedAuthenticationInfo() { getAuthenticationCache().clear(); } public void clearAllCache() { clearAllCachedAuthorizationInfo(); clearAllCachedAuthenticationInfo(); } }
在这里有一个这样的一个类Principal这个类的作用主要是在用户登录的时候shiro保存登录信息,包括id ,姓名,密码,状态。等等。可以自定义。在JSP标签里的输出对象,在下面有讲。
前台登录controller:
package 系统路径.controller.usermember; import org.apache.commons.lang.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.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import com.alibaba.fastjson.JSON; import 系统路径.前台用户实体类.Principal; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @Controller @RequestMapping("userMember") public class UserMemberController extends BaseController<UserMemberDO> { /** * logger日志 */ protected Logger logger = LoggerFactory.getLogger(getClass()); /** * 序列化id */ private static final long serialVersionUID = -2271706136984114038L; /** * 登录 * @param request 请求 * @param response 响应 * @param member 前台用户对象 * @param model 模板 * @return String 页面 */ @RequestMapping(value = "/login") public String login(HttpServletRequest request, HttpServletResponse response, @ModelAttribute("member") UserMemberDO member, ModelMap model) { logger.info("login..."); Subject subject = SecurityUtils.getSubject(); Principal principal = (Principal) subject.getPrincipal(); // 如果已经登录,则跳转到管理首页 if (principal != null) { return "redirect:/home/forward"; // 首页 } String exceptionClassName = (String) request.getAttribute("shiroLoginFailure"); String errorMsg = null; if (UnknownAccountException.class.getName().equals(exceptionClassName)) { logger.info("该用户名不存在"); errorMsg = "该用户名不存在"; } else if (IncorrectCredentialsException.class.getName().equals(exceptionClassName)) { logger.info("密码错误"); errorMsg = "密码错误"; } else if (DisabledAccountException.class.getName().equals(exceptionClassName)) { logger.info("该账号审核未通过"); errorMsg = "该账号审核未通过"; } else if (exceptionClassName != null) { logger.info("登录错误" + exceptionClassName); errorMsg = "登录错误"; } model.addAttribute("errorMsg", errorMsg); return PAGE_LOGIN; } }
这里我只写出前台登录的controller,后台的登录controller一样就不贴出了。
在JSP页面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ include file="/view/common/include.jsp"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登录</title> <script type="text/javascript" src="${ctxStatic }/js/login/login.js"></script> <script> </script> </head> <body> <div class="container-login" id="div1"> <img src="${ctxStatic }/img/bj.png" /> </div> <div class="container-login" id="div1"> <img src="${ctxStatic }/img/bj.png" /> </div> <div class="content-all-login"> <div class="content-login"> <form action="${ctx}/userMember/login" method="post" id="loginform" > <div class="content-title"> <h3>登录</h3> </div> <div class="form-group"> <input type="text" id="name" name="name" class="form-control text1" value="tom123" placeholder="输入用户名"/> </div> <div class="form-group"> <input type="password" id="password" name="password" value="000000"class="form-control text2" placeholder="密码"/> <input type="text" id="logintype" name="logintype" value="0" style="display:none"/> </div> <div class="wrong"><label id="errorMsg">${errorMsg}</label></div> <div class="row row-mian"> <div class="col-sm-6" style="padding-left: 0px;text-align: left;"> <input type="checkbox" value="true" id="rememberMe" name="rememberMe"/> <span class="login-seven">七天免登陆<span> </div> <div class="col-sm-6" style="padding-right: 0px;text-align: right;"> <a href="" class="forgetPassword">忘记密码</a> </div> <div> <button type="submit"class="btn btn-primary" style="margin-top: 25px;width: 232px;background: #0094fd;height: 40px;">登录</button> </div> </div> </form> </div> </div> </body> </html>
登录成功以后,如何显示的登录者的用户名。在这里shrio有自己的页面标签:
首先导入 标签:
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<shiro:guest> <a href=""">登录</a>| <a href="" class="registered">注册</a> </shiro:guest>
<shiro:user> <a class="login">你好:[<shiro:principal property="name"/>]</a> <span id="center-info"> <ul> <li class="dropdown" id="accountmenu" style="margin-right: 0px;"> <a class="center-in" style="width: 130px;display: inline-block;font-weight: 400;"> 个人中心<b class="caret"></b></a> <ul class="dropdown-menu" style="display: none;" id="center"> <li><a href="${ctx}/userMember/center" style="font-weight: 400;">基本信息</a></li> <li><a href="${ctx}/userMember/history" style="font-weight: 400;">历史申请记录</a></li> </ul> </li> </ul> </span> <a href="${ctx }/alter/message" class="login">消息</a> <a href="${ctx }/logout" class="login">退出</a> </shiro:user>
这里详细的就不贴出了,也就不详细说明了。只是告诉大家,有这样一个途径,就不用费尽心思的还要把信息封装到session 里面了。一开始,我不知道有这样的途径,所以,把信息封装到了session里面了,这真的是多此一举。
评论