标签:setter shared util mis 创建 全局 idt isp val
1 <mvc:interceptors> 2 <mvc:interceptor> 3 <mvc:mapping path="/**"/> 4 <!--拦截的url --> 5 <mvc:mapping path="/admin/**"/> 6 <!-- 不拦截的url start --> 7 <mvc:exclude-mapping path="/admin/login"/> 8 <mvc:exclude-mapping path="/admin/code"/> 9 <mvc:exclude-mapping path="/admin/logout"/> 10 <mvc:exclude-mapping path="/admin/msgErrorInfo"/> 11 <!--不拦截的url end --> 12 <bean class="authorizing.RequestInterceptor"> 13 <property name="unauthenticatedUrl" value="/admin/msgErrorInfo" /> 14 </bean> 15 </mvc:interceptor> 16 </mvc:interceptors>
1 public class RequestInterceptor extends HandlerInterceptorAdapter { 2 3 private String unauthenticatedUrl; 4 5 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 6 Object handler) throws Exception { 7 if(PermissionUtils.isLogin(request)){ 8 return true; 9 } 10 //token已失效,返回提示信息 11 request.getRequestDispatcher(unauthenticatedUrl).forward(request, response); 12 return false; 13 } 14 15 public void setUnauthenticatedUrl(String unauthenticatedUrl) { 16 this.unauthenticatedUrl = unauthenticatedUrl; 17 } 18 }
1 public class PermissionUtils { 2 private static ThreadLocal<String> sessionToken = new ThreadLocal<String>(); 3 4 public static boolean isLogin(HttpServletRequest request){ 5 String token = sessionToken(request); 6 if(StringUtils.isEmpty(token)) 7 return false; 8 /** 9 * 使用token检查是否存在登录session 10 */ 11 //Session session = SecurityUtils.getSecurityManager().getSession(new WebSessionKey(token, request, response)); 12 Session session = SecurityUtils.getSecurityManager().getSession(new DefaultSessionKey(token)); 13 if(session != null){ 14 session.touch(); 15 sessionToken.set(token); 16 return true; 17 } 18 return false; 19 } 20 21 private static String sessionToken(HttpServletRequest request){ 22 return request.getHeader("token"); 23 } 24 }
<bean id="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager"> <property name="realm" ref="authorizingRealm" /> <property name="sessionManager"> <bean class="service.authorizing.shiro.RedisSessionManager" > <property name="globalSessionTimeout" value="${session.timeout}" /> </bean> </property> </bean> <bean id="realmCache" class="service.authorizing.shiro.cache.RedisShiroCache" /> <bean id="authorizingRealm" class="service.authorizing.shiro.DefaultAuthorizingRealm"> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCache" ref="realmCache" /> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean>
1 public class DefaultAuthorizingRealm extends AuthorizingRealm { 2 3 @Autowired 4 private AuthorizingService authorizingService; 5 6 /** 7 * 获取登录用户角色和功能权限信息, 8 * 使用{@link org.apache.shiro.cache.CacheManager}和{@link org.apache.shiro.cache.Cache}获取数据. 9 * @param principals 登录用户ID 10 * @return 11 */ 12 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 13 Object username =principals.getPrimaryPrincipal(); 14 Cache<Object, AuthorizationInfo> infoCache = getAuthorizationCache(); 15 AuthorizationInfo info = infoCache.get(username); 16 return info; 17 } 18 19 /** 20 * 根据登录用户token,获取用户信息。 21 * 对于session timeout时间较短的场景可以考虑使用AuthenticationCache 22 * 若验证失败,会抛出异常 {@link AuthenticationException} 23 * @param token 24 * @return 25 * @throws AuthenticationException 26 */ 27 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 28 Object username = token.getPrincipal(); 29 //对于session timeout时间较短的场景,可缓存用户authentication信息 30 //Cache<Object, AuthenticationInfo> infoCache = getAuthenticationCache(); 31 //return infoCache.get(username); 32 return authorizingService.authentication(username); 33 } 34 }
1 @Controller 2 @RequestMapping("/admin") 3 public class LoginController { 4 Logger logger = LoggerFactory.getLogger(LoginController.class); 5 6 @Autowired 7 private AuthorizingService authorizingService; 8 9 @RequestMapping("/login") 10 @ResponseBody 11 public LoginToken login(User user, HttpServletRequest request){ 12 Subject subject = new Subject.Builder().buildSubject(); 13 UsernamePasswordToken token = new UsernamePasswordToken(userName, UtilTool.md5Tool(password)); 14 token.setRememberMe(true); 15 LoginToken loginToken = new LoginToken(); 16 try{ 17 subject.login(token); 18 Session session = subject.getSession(); 19 user.setToken((String) session.getId()); 20 loginToken.setResultCode(WebConstants.RESULT_SUCCESS_CODE); 21 } catch (AuthenticationException e) { 22 loginToken.setResultCode(WebConstants.RESULT_FAIL_CODE); 23 loginToken.setMessage("用户名或密码错误!"); 24 } 25 return loginToken; 26 } 27 }
1 private static AuthorizingService authorizingService; 2 3 private static ThreadLocal<String> sessionToken = new ThreadLocal<String>(); 4 5 /** 6 * 7 * @param url eg: /admin/review 8 * @param argv eg: WAIT_BIZ_MANAGER 9 */ 10 public static void checkPermission(String url, @Nullable String argv){ 11 Subject subject = getSubject(); 12 String permissionCode = authorizingService.uriMappingCode(url, argv); 13 if(StringUtils.isEmpty(permissionCode)) 14 throw new IllegalArgumentException("不明操作"); 15 subject.checkPermission(permissionCode); 16 } 17 18 public static Subject getSubject(){ 19 String token = sessionToken.get(); 20 if(StringUtils.isEmpty(token)) 21 throw new AuthenticationException("未经认证"); 22 return new Subject.Builder() 23 .sessionId(sessionToken.get()) 24 .buildSubject(); 25 } 26 27 public static void setAuthorizingService(AuthorizingService authorizingService) { 28 PermissionUtils.authorizingService = authorizingService; 29 }
1 @RestController 2 @RequestMapping(value = "/review") 3 public class ReviewApiController { 4 5 @Autowired 6 private ReviewService reviewService; 7 8 @ResponseBody 9 @RequestMapping(value = "/review", method = POST) 10 public WebResult review(@RequestBody NewReviewVo reviewVo){ 11 //检查访问权限 12 PermissionUtils.checkPermission("/review/review", reviewVo.getFeatureCode()); 13 WebResult result = WebResult.successResult(); 14 try { 15 Review review = ReviewAssembler.voToReview(reviewVo); 16 reviewService.review(review); 17 }catch (Exception e){ 18 result = WebResult.failureResult(e.getMessage()); 19 } 20 return result; 21 } 22 }
1 /** 2 * 根据 attributeKey,有选择的缓存session信息; 3 * 设置 {@parm enabledSharedSessionData}来有选择的启用共享session功能。 4 */ 5 public class RedisSessionManager extends DefaultSessionManager { 6 7 private static Logger logger = LoggerFactory.getLogger(RedisSessionManager.class); 8 9 private boolean enabledSharedSessionData; 10 11 private Set<String> sharedSessionDataKeys; 12 13 public RedisSessionManager() { 14 enabledSharedSessionData = true; 15 sharedSessionDataKeys = new HashSet<String>(); 16 } 17 18 @Override 19 public Collection<Object> getAttributeKeys(SessionKey key) { 20 21 Collection<Object> keys = super.getAttributeKeys(key); 22 if(enabledSharedSessionData) { 23 /** 24 * 从redis获取 {@param key} 对应session的所有attribute key 25 */ 26 Set sharedKeys = RedisClient.extractAttributeKey((String) key.getSessionId()); 27 keys.addAll(sharedKeys); 28 } 29 return keys; 30 } 31 32 @Override 33 public Object getAttribute(SessionKey sessionKey, Object attributeKey) 34 throws InvalidSessionException { 35 if(checkSharedStrategy(attributeKey)){ 36 Object object = RedisClient.getValue((String) attributeKey, (String) sessionKey.getSessionId()); 37 return object; 38 } 39 return super.getAttribute(sessionKey, attributeKey); 40 } 41 42 @Override 43 public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) 44 throws InvalidSessionException { 45 if(checkSharedStrategy(attributeKey)) { 46 if(value instanceof Serializable) 47 RedisClient.setValue((String) attributeKey, (String) sessionKey.getSessionId(), 48 (Serializable) value, getGlobalSessionTimeout(), TimeUnit.MILLISECONDS); 49 else 50 throw new IllegalArgumentException("不可共享非序列化value"); 51 return; 52 } 53 super.setAttribute(sessionKey, attributeKey, value); 54 } 55 56 private boolean checkSharedStrategy(Object attributeKey){ 57 return enabledSharedSessionData && sharedSessionDataKeys.contains(attributeKey); 58 } 59 60 /** 61 * 如果是集群, session只在一台机器上创建,因此必须共享 SessionId。 62 * 当request发过来,获取request中携带的 SessionId,使用 SessionId 在本地获取session, 63 * 如果为null,则用 SessionId 去redis检查是否存在,如果存在则在本地构建session返回 64 * (实际就是{@link SimpleSession}的代理{@link DelegatingSession},{@see RedisSessionManager#restoreSession}), 65 * 否则返回空, 请求重新登录。 66 * {@link org.apache.shiro.session.mgt.AbstractNativeSessionManager#getSession(SessionKey)} 67 * @param key 68 * @return 69 * @throws SessionException 70 */ 71 @Override 72 public Session getSession(SessionKey key) throws SessionException { 73 Session session = null; 74 try { 75 session = getLocalSession(key); 76 } catch (UnknownSessionException use){ 77 //ignored 78 session = null; 79 } 80 if(!enabledSharedSessionData || session != null) 81 return session; 82 /** 83 * 检查redis,判断session是否已创建, 84 * 若已创建,则使用SessionFactory在本地构建SimpleSession 85 */ 86 Serializable sid = RedisClient.getValue((String) key.getSessionId()); 87 if(sid != null){ 88 session = restoreSession(key); 89 } 90 91 return session; 92 } 93 94 /** 95 * 每一次通过 96 * {@link org.apache.shiro.session.mgt.AbstractValidatingSessionManager#doGetSession(SessionKey)}} 97 * 获取session 98 * 或是通过{@link org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler} 99 * 定时检查,都会去调用 100 * {@link org.apache.shiro.session.mgt.AbstractValidatingSessionManager#doValidate(Session)} 101 * 验证session是否过期。 102 * 共享session过期的标准是该redis中sessionId过期, 由于redis已经帮助完成了session过期检查, 103 * 所以这里只需要定期清理本地内存中的过期session。 104 * 然而{@link org.apache.shiro.session.mgt.AbstractValidatingSessionManager#doGetSession(SessionKey)}} 105 * 是一个final方法,无法被overwrite,所以只能copy Shiro原来的代码实现来定义getLocalSession(SessionKey key) 106 * @param key 107 * @return 108 */ 109 private Session getLocalSession(SessionKey key){ 110 Session session = lookupSession(key); 111 return session != null ? createExposedSession(session, key) : null; 112 } 113 private Session lookupSession(SessionKey key) throws SessionException { 114 if (key == null) { 115 throw new NullPointerException("SessionKey argument cannot be null."); 116 } 117 //enableSessionValidationIfNecessary 118 SessionValidationScheduler scheduler = getSessionValidationScheduler(); 119 if (enabledSharedSessionData || 120 (isSessionValidationSchedulerEnabled() && (scheduler == null || !scheduler.isEnabled())) 121 ) { 122 enableSessionValidation(); 123 } 124 Session s = retrieveSession(key); 125 if (!enabledSharedSessionData && s != null) { 126 validate(s, key); 127 } 128 return s; 129 } 130 131 /** 132 * 根据{@link SessionKey}以及继承自{@link DefaultSessionManager}的默认创建方法, 133 * 重新在本地构建session。 134 * @param key 135 * @return 136 */ 137 private Session restoreSession(SessionKey key){ 138 SimpleSession restoreSession = (SimpleSession) getSessionFactory().createSession(null); 139 restoreSession.setId(key.getSessionId()); 140 restoreSession.setTimeout(getGlobalSessionTimeout()); 141 create(restoreSession); 142 return createExposedSession(restoreSession, key); 143 } 144 145 /** 146 * 开启一个新的session, 并且在新的session开启之后做一系列的session共享工作。 147 * {@link org.apache.shiro.session.mgt.AbstractNativeSessionManager#start(SessionContext)} 148 * @param context 149 * @return 150 */ 151 @Override 152 public Session start(SessionContext context) { 153 Session session = super.start(context); 154 if(enabledSharedSessionData){ 155 shareSessionData(session); 156 } 157 return session; 158 } 159 /** 160 * 完成session基本数据共享 161 */ 162 private void shareSessionData(Session session){ 163 refreshTTL(session.getId()); 164 } 165 /** 166 * 刷新session存活时间 167 */ 168 private void refreshTTL(Serializable sessionId){ 169 RedisClient.setValue((String) sessionId, new Date(), 170 getGlobalSessionTimeout(), TimeUnit.MILLISECONDS); 171 } 172 173 /** 174 * {@link org.apache.shiro.session.mgt.AbstractNativeSessionManager#touch(SessionKey)} 175 * @param key 176 * @throws InvalidSessionException 177 */ 178 @Override 179 public void touch(SessionKey key) throws InvalidSessionException { 180 if(enabledSharedSessionData){ 181 //刷新session存活时间 182 refreshTTL(key.getSessionId()); 183 } 184 super.touch(key); 185 } 186 187 /** 188 * 当主动调用{@link Subject#logout()}时,相应会调用该方法来停止session。 189 * 因此,如果共享了session,也需要即时清除共享session。 190 * {@link org.apache.shiro.session.mgt.AbstractNativeSessionManager#stop(SessionKey)} 191 * @param key 192 * @throws InvalidSessionException 193 */ 194 @Override 195 public void stop(SessionKey key) throws InvalidSessionException { 196 super.stop(key); 197 if(enabledSharedSessionData) 198 RedisClient.delete((String) key.getSessionId()); 199 } 200 201 /** 202 * {@link org.apache.shiro.session.mgt.AbstractNativeSessionManager#getLastAccessTime(SessionKey)} 203 * @param key 204 * @return 205 */ 206 @Override 207 public Date getLastAccessTime(SessionKey key) { 208 Serializable lastAccessTime = enabledSharedSessionData ? 209 RedisUtils.getValue((String) key.getSessionId()) : 210 super.getLastAccessTime(key); 211 if(lastAccessTime == null) 212 throw new SessionTimeoutException(); 213 return (Date) lastAccessTime; 214 } 215 216 /** 217 * 通知session manager那些attribute key对应的数据需要共享。 218 * @param key 219 */ 220 public void registerSharedAttributeKey(String key){ 221 if(!enabledSharedSessionData) 222 throw new IllegalArgumentException("不允许共享session数据"); 223 if(sharedSessionDataKeys == null) 224 sharedSessionDataKeys = new HashSet<String>(); 225 sharedSessionDataKeys.add(key); 226 } 227 }
图4 Authentication时序
图4 Authorization时序
标签:setter shared util mis 创建 全局 idt isp val
原文地址:http://www.cnblogs.com/shenjixiaodao/p/7426594.html