sessionId控制单点登陆
1.配置security-context.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">
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="2592000"/><!-- 30天 -->
</bean>
<!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<!-- rememberMe cookie加密的密钥 每个项目都不一样 默认AES算法 用下面的代码产生不同的密码
AesCipherService aes = new AesCipherService();
byte[] key = aes.generateNewKey().getEncoded();
String base64 = Base64.encodeToString(key);
-->
<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('kbFQXD6nkE8QuvzqlV9UYA==')}"/>
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="securityService"/>
<!-- 可以配置多个Realm,其实会把realms属性赋值给ModularRealmAuthenticator的realms属性 -->
<!--<property name="realms">-->
<!--<list>-->
<!--<ref bean="securityService" />-->
<!--<ref bean="frontSecurityService"/>-->
<!--</list>-->
<!--</property>-->
<property name="rememberMeManager" ref="rememberMeManager"/>
<property name="sessionManager" ref="sessionManager"/>
<!--单点登陆的配置代码开始-->
<property name="authenticator.authenticationListeners">
<list>
<ref bean="securityService"/>
</list>
</property>
<!--单点登陆代码结束-->
</bean>
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="sessionValidationInterval" value="60000"/>
<property name="globalSessionTimeout" value="300000"/>
</bean>
<!-- 配置使用自定义认证器,可以实现多Realm认证,并且可以指定特定Realm处理特定类型的验证 -->
<!--<bean id="authenticator" class="im.lsn.oss.exhibition.shiro.CustomizedModularRealmAuthenticator">-->
<!--<!– 配置认证策略,只要有一个Realm认证成功即可,并且返回所有认证成功信息 –>-->
<!--<property name="authenticationStrategy">-->
<!--<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>-->
<!--</property>-->
<!--</bean>-->
<!--<bean id="frontSecurityService" class="im.lsn.oss.exhibition.service.FrontSecurityService">-->
<!--<!– 配置密码匹配器 –>-->
<!--<property name="credentialsMatcher">-->
<!--<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">-->
<!--<!– 加密算法为MD5 –>-->
<!--<property name="hashAlgorithmName" value="MD5"></property>-->
<!--<!– 加密次数 –>-->
<!--<property name="hashIterations" value="1024"></property>-->
<!--</bean>-->
<!--</property>-->
<!--</bean>-->
<bean id="formAuthenticationTenantFilter" class="im.lsn.oss.exhibition.web.admin.Security.AdminFilter"/>
<bean id="frontFilter" class="im.lsn.oss.exhibition.web.front.Security.FrontFilter"/> <bean id="authShiroFilter" class="im.lsn.oss.exhibition.web.filter.AuthShiroFilter"/> <bean id="logout" class="im.lsn.oss.exhibition.web.MyLogoutFilter"> <property name="redirectUrl" value="/jsp/login.jsp"/> <property name="frontRedirectUrl" value="/front/index.do"/> </bean> <bean id="shiroSecurityFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/jsp/login.jsp"/> <property name="successUrl" value="/jsp/login_success.jsp"/> <property name="filters"> <map> <entry key="authc" value-ref="formAuthenticationTenantFilter"/> <entry key="rolesor" value-ref="authShiroFilter"/> <entry key="logout" value-ref="logout"/> <entry key="front" value-ref="frontFilter"/> </map> </property> <property name="filterChainDefinitions"> <value> /jsp/login.jsp = authc /logout = logout <!--/f/logout = logout--> <!--/jsp/front/user_login.jsp = front--> <!--/front/visitor/user/*= front--> <!--/front/visitor/user_favorites.do=front--> /admin/index.do = rolesor[admin,operator_admin,venue_admin,organizer_admin,exhibitors_admin] /admin/organizer/exhibitorInfoListing.do = rolesor[admin,operator_admin,venue_admin,organizer_admin] /admin/organizer/exhibitorInfoList.do = rolesor[admin,operator_admin,venue_admin,organizer_admin] /admin/organizer/verify.do = rolesor[admin,operator_admin,venue_admin,organizer_admin] /admin/organizer/save_verify.do = rolesor[admin,operator_admin,venue_admin] /admin/organizer/exhibitor_info_index.do = rolesor[admin,operator_admin,venue_admin,organizer_admin] /admin/organizer/fail_exhibitorInfoList.do = rolesor[admin,operator_admin,venue_admin,organizer_admin] /admin/organizer/hotRecommend.do = rolesor[admin,operator_admin,venue_admin] /admin/organizer/identifierList.do = rolesor[admin,operator_admin,venue_admin,organizer_admin] /admin/exhibitors/wait_index.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/booth_index.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/fail_index.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/booth_preview.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/mark.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/save_mark.do = rolesor[admin,operator_admin,organizer_admin] /admin/exhibitors/edit_booth_venue_branch.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/wait_product.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/product_index.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/fail_product.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/product_preview.do = rolesor[admin,operator_admin,organizer_admin,exhibitors_admin] /admin/exhibitors/ProductHotRecommend.do = rolesor[admin,operator_admin,organizer_admin] /admin/information/** = rolesor[admin,operator_admin] /admin/log/** = rolesor[admin,operator_admin] /admin/user/** = rolesor[admin,operator_admin,venue_admin,organizer_admin,exhibitors_admin] /admin/user/index.do = rolesor[admin,operator_admin] /admin/venue/** = rolesor[admin,operator_admin,venue_admin] /admin/organizer/** = rolesor[admin,venue_admin,organizer_admin] /admin/exhibitors/** = rolesor[admin,organizer_admin,exhibitors_admin] /admin/venue/index.do = rolesor[admin,operator_admin] /admin/organizer/index.do = rolesor[admin,venue_admin] /admin/operator/edit.do = rolesor[admin,operator_admin] /admin/** = rolesor[admin] </value> </property> </bean></beans>
2.security
import im.lsn.framework.BusinessLogicException; import im.lsn.framework.jpa.JpaRepositoryImpl; import im.lsn.framework.shrio.CustomSecurityException; import im.lsn.oss.exhibition.entity.*; import im.lsn.oss.exhibition.entity.enumerate.LoginType; import im.lsn.oss.exhibition.entity.enumerate.VistorType; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; 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.session.Session; import org.apache.shiro.session.mgt.DefaultSessionManager; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.DigestUtils; import javax.annotation.PostConstruct; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.Collection; import java.util.Date; /** * Created by fireflyc on 2017/4/26. */ @Service @Transactional public class SecurityService extends AuthorizingRealm implements AuthenticationListener{ private Logger LOGGER = LoggerFactory.getLogger(SecurityService.class); @Autowired UserService userService; @Autowired private ClickedCountService clickedCountService; @Autowired private DefaultSessionManager sessionManager; @PersistenceContext protected EntityManager entityManager; private JpaRepositoryImpl<TbUser, Long> userRepository; private JpaRepositoryImpl<TbRole, Long> roleRepository; private JpaRepositoryImpl<TbUserState, Long> userStateLongJpaRepository; private JpaRepositoryImpl<TbType, Long> typeLongJpaRepository; private JpaRepositoryImpl<TbExhibitionUser, Long> exhibitionUserLongJpaRepository; @PostConstruct public void initSecurityService() { this.userRepository = new JpaRepositoryImpl<TbUser, Long>(TbUser.class, entityManager); this.roleRepository = new JpaRepositoryImpl<TbRole, Long>(TbRole.class, entityManager); this.userStateLongJpaRepository = new JpaRepositoryImpl<TbUserState, Long>(TbUserState.class, entityManager); this.exhibitionUserLongJpaRepository = new JpaRepositoryImpl<TbExhibitionUser, Long>(TbExhibitionUser.class, entityManager); this.typeLongJpaRepository = new JpaRepositoryImpl<TbType, Long>(TbType.class, entityManager); HashedCredentialsMatcher matcher = new HashedCredentialsMatcher("MD5"); setCredentialsMatcher(matcher); } @EventListener public void createAdminAccount(ContextRefreshedEvent event) { TbRole role = roleRepository.findOne(QTbRole.tbRole.id.eq(1L)); if (role == null) { role = new TbRole(); role.setRoleName("系统管理员"); role.setRoleCnName("admin"); roleRepository.save(role); LOGGER.info("创建系统管理员角色"); } TbUser user = userRepository.findOne(QTbUser.tbUser.id.eq(1L)); TbUserState userState = userStateLongJpaRepository.findOne(1L); TbType type = typeLongJpaRepository.findOne(1L); if (user == null) { user = new TbUser(); user.setId(1L); user.setCreateTime(new Date()); user.setRole(role); user.setUsername("admin_tontron"); user.setNickname("系统管理员"); String password = "admin_tontron" + DigestUtils.md5DigestAsHex("Tontron1169".getBytes()); user.setPassword(password); user.setState(userState); user.setType(type); userRepository.save(user); LOGGER.info("创建系统管理员"); } } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { UserLoginToken userToken = (UserLoginToken) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); if (userToken.getType().equals(LoginType.ADMIN.toString())) { authorizationInfo.addRole(userToken.getRole().getRoleName()); } else { authorizationInfo.addRole(userToken.getFrontRole()); } return authorizationInfo; } public void logout() { SecurityUtils.getSubject().logout(); } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { if (authcToken instanceof UsernamePasswordToken) { CustomizedToken token = (CustomizedToken) authcToken; if (token.getLoginType().equals(LoginType.ADMIN.toString())) { try { QTbUser qUser = QTbUser.tbUser; TbUser user = userRepository.findOne(qUser.username.eq(token.getUsername())); TbUserState userState = userStateLongJpaRepository.findOne(2L); if (user == null) { throw new UnknownAccountException(); } if (user.getState().getStateName().equals(userState.getStateName())) { throw new BusinessLogicException("账号被禁用,无法登录"); } if(null != user.getClickedCount() && 5<user.getClickedCount()){ Integer count = user.getClickedCount(); count++; clickedCountService.updateClickedCount(user.getId(),count); throw new BusinessLogicException("登陆失败次数过多,请明天再尝试"); } LOGGER.info("用户{} 存在", user.getNickname()); String showName = user.getNickname(); if (null == showName || showName.length() == 0) { showName = userService.searchShowNameForUser(user); } UserLoginToken loginToken = new UserLoginToken(); loginToken.setUserId(user.getId()); loginToken.setUserName(user.getUsername()); loginToken.setNickName(user.getNickname()); loginToken.setRole(user.getRole()); loginToken.setShowName(showName); loginToken.setType(token.getLoginType()); loginToken.setSubUser(user.getSubUser()); return new SimpleAuthenticationInfo(loginToken, user.getPassword(), getName()); } catch (BusinessLogicException e) { throw new CustomSecurityException(e.getMessage()); } catch (Exception e) { LOGGER.error(e.getMessage(), e); if (e instanceof UnknownAccountException) { throw new UnknownAccountException(); } else { throw new CustomSecurityException("用户名或密码错误"); } } } else { try { QTbExhibitionUser qTbExhibitionUser = QTbExhibitionUser.tbExhibitionUser; TbExhibitionUser exhibitionUser = exhibitionUserLongJpaRepository.findOne(qTbExhibitionUser.phone.eq(token.getUsername())); if (exhibitionUser == null) { throw new UnknownAccountException(); } LOGGER.info("用户{} 存在", exhibitionUser.getPhone()); UserLoginToken loginToken = new UserLoginToken(); loginToken.setUserId(exhibitionUser.getId()); loginToken.setUserName(exhibitionUser.getPhone()); loginToken.setFrontRole(VistorType.EXHIBITOR_USER.getName()); loginToken.setShowName(exhibitionUser.getPhone()); loginToken.setType(token.getLoginType()); return new SimpleAuthenticationInfo(loginToken, exhibitionUser.getPassword(), getName()); } catch (BusinessLogicException e) { throw new CustomSecurityException(e.getMessage()); } catch (Exception e) { LOGGER.error(e.getMessage(), e); throw new CustomSecurityException("用户名或密码错误"); } } } return null; } public UserLoginToken getLoginToken() { try { Subject subject = SecurityUtils.getSubject(); if (subject == null) { return null; } return (UserLoginToken) subject.getPrincipal(); } catch (Exception e) { LOGGER.error(e.getMessage(), e); return null; } } public TbUser getLoginUser() { UserLoginToken loginToken = getLoginToken(); Assert.notNull(loginToken); TbUser tbUser = userRepository.selectFrom(QTbUser.tbUser) .where(QTbUser.tbUser.id.eq(loginToken.getUserId())).fetchOne(); return tbUser; } public TbExhibitionUser getFrontLoginUser() { UserLoginToken loginToken = getLoginToken(); Assert.notNull(loginToken); TbExhibitionUser exhibitionUser = exhibitionUserLongJpaRepository.selectFrom(QTbExhibitionUser.tbExhibitionUser) .where(QTbExhibitionUser.tbExhibitionUser.id.eq(loginToken.getUserId())).fetchOne(); return exhibitionUser; } //单点登陆的java代码 public void onSuccess(AuthenticationToken token, AuthenticationInfo info){ Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken loginToken = (UsernamePasswordToken) token; Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions(); for (Session session : sessions) { Subject sub = new Subject.Builder().session(session).buildSubject(); if (sub.isAuthenticated()) { UserLoginToken other = (UserLoginToken) sub.getPrincipal(); if (other.getUserName().equals(loginToken.getUsername())) { if (!session.getId().equals(subject.getSession().getId())) { session.stop(); } } } } } public void onFailure(AuthenticationToken var1, AuthenticationException var2){ } public void onLogout(PrincipalCollection var1){ } //单点登陆的java代码结束 }