1. 程式人生 > >sessionId控制單點登陸

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">-->
<!--&lt;!&ndash; 配置認證策略,只要有一個Realm認證成功即可,並且返回所有認證成功資訊 &ndash;&gt;-->
<!--<property name="authenticationStrategy">-->
<!--<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>-->
<!--</property>-->
<!--</bean>-->


<!--<bean id="frontSecurityService" class="im.lsn.oss.exhibition.service.FrontSecurityService">-->
<!--&lt;!&ndash; 配置密碼匹配器 &ndash;&gt;-->
<!--<property name="credentialsMatcher">-->
<!--<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">-->
<!--&lt;!&ndash; 加密演算法為MD5 &ndash;&gt;-->
<!--<property name="hashAlgorithmName" value="MD5"></property>-->
<!--&lt;!&ndash; 加密次數 &ndash;&gt;-->
<!--<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程式碼結束 }