当前位置: 首页 > news >正文

东莞旅游网站建设自助网站免费建站平台

东莞旅游网站建设,自助网站免费建站平台,wordpress 用户排序,.net做网站用什么的多目录 1.用户登录认证流程 1.1 生成认证Token 1.2 用户登录认证 1.2.1 SecurityManager login流程解析 1.2.1.1 authenticate方法进行登录认证 1.2.1.1.1 单Realm认证 1.2.1.2 认证通过后创建登录用户对象 1.2.1.2.1 复制SubjectContext 1.2.1.2.2 对subjectContext设…目录 1.用户登录认证流程 1.1 生成认证Token 1.2 用户登录认证 1.2.1  SecurityManager login流程解析 1.2.1.1 authenticate方法进行登录认证 1.2.1.1.1 单Realm认证 1.2.1.2 认证通过后创建登录用户对象 1.2.1.2.1 复制SubjectContext 1.2.1.2.2 对subjectContext设置securityManager 1.2.1.2.3 对subjectContext设置session 1.2.1.2.4 对subjectContext设置Principals 1.2.1.2.5 根据subjectContext创建Subject 1.2.1.2.6 保存Subject  Shiro作为一款比较流行的登录认证、访问控制安全框架被广泛应用在程序员社区Shiro登录验证、访问控制、Session管理等流程内部都是委托给SecurityManager安全管理器来完成的SecurityManager安全管理器上篇文章已经进行了详细解析详见Shiro框架Shiro SecurityManager安全管理器解析-CSDN博客在此基础上本篇文章继续对Shiro关联链路处理流程之一---登录认证流程 进行解析 想要深入了解Shiro框架整体原理可移步 Shiro框架ShiroFilterFactoryBean过滤器源码解析-CSDN博客、 Shiro框架Shiro内置过滤器源码解析-CSDN博客 1.用户登录认证流程 在Shiro框架Shiro内置过滤器源码解析-CSDN博客内置过滤器分析中我们知道用户执行登录的认证操作是在过滤器FormAuthenticationFilter中执行的如下 protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {if (isLoginRequest(request, response)) {if (isLoginSubmission(request, response)) {if (log.isTraceEnabled()) {log.trace(Login submission detected. Attempting to execute login.);}return executeLogin(request, response);} else {if (log.isTraceEnabled()) {log.trace(Login page view.);}//allow them to see the login page ;)return true;}} else {if (log.isTraceEnabled()) {log.trace(Attempting to access a path which requires authentication. Forwarding to the Authentication url [ getLoginUrl() ]);}saveRequestAndRedirectToLogin(request, response);return false;}}登录认证操作是在executeLogin方法中完成的 protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {AuthenticationToken token createToken(request, response);if (token null) {String msg createToken method implementation returned null. A valid non-null AuthenticationToken must be created in order to execute a login attempt.;throw new IllegalStateException(msg);}try {Subject subject getSubject(request, response);subject.login(token);return onLoginSuccess(token, subject, request, response);} catch (AuthenticationException e) {return onLoginFailure(token, e, request, response);}} 上述源码的执行过程表示为时序图会更直观时序图如下 该认证过程主要包含以下几个部分 根据用户名密码等生成认证Token获取当前登录用户Subject调用Subject的login方法进行登录认证其它的登录成功、或登录失败的拦截方法 下面主要对生成认证Token和用户登录认证实现进行详细说明 1.1 生成认证Token createToken的实现在FormAuthenticationFilter内如下 这里用户名和密码是通过request请求对象获取的 protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {String username getUsername(request);String password getPassword(request);return createToken(username, password, request, response);} 在父类AuthenticatingFilter中进一步实现如下这里构造了UsernamePasswordToken类表示采用用户名密码的认证方式 protected AuthenticationToken createToken(String username, String password,ServletRequest request, ServletResponse response) {boolean rememberMe isRememberMe(request);String host getHost(request);return createToken(username, password, rememberMe, host);}protected AuthenticationToken createToken(String username, String password,boolean rememberMe, String host) {return new UsernamePasswordToken(username, password, rememberMe, host);} 图示UsernamePasswordToken的继承结构 1.2 用户登录认证 在Subject的login的具体实现如下 实际的login是委托给SecurityManager完成的登录成功后设置当前登录对象为认证成功 下面主要对SecurityManager的login方法进行具体分析  1.2.1  SecurityManager login流程解析 login方法具体实现如下 public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {AuthenticationInfo info;try {info authenticate(token);} catch (AuthenticationException ae) {try {onFailedLogin(token, ae, subject);} catch (Exception e) {if (log.isInfoEnabled()) {log.info(onFailedLogin method threw an exception. Logging and propagating original AuthenticationException., e);}}throw ae; //propagate}Subject loggedIn createSubject(token, info, subject);onSuccessfulLogin(token, info, loggedIn);return loggedIn;} 上述登录流程主要包含2部分内容  通过authenticate方法进行登录认证认证通过后创建登录用户对象 下面分别进行展开分析 1.2.1.1 authenticate方法进行登录认证 具体的authenticate实现内部又委托给了认证器Authenticator来实现具体的认证器为ModularRealmAuthenticator其继承结构如下 authenticate方法具体实现是在父类AbstractAuthenticator中如下 public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {if (token null) {throw new IllegalArgumentException(Method argument (authentication token) cannot be null.);}log.trace(Authentication attempt received for token [{}], token);AuthenticationInfo info;try {info doAuthenticate(token);if (info null) {String msg No account information found for authentication token [ token ] by this Authenticator instance. Please check that it is configured correctly.;throw new AuthenticationException(msg);}} catch (Throwable t) {AuthenticationException ae null;if (t instanceof AuthenticationException) {ae (AuthenticationException) t;}if (ae null) {//Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more//severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate:String msg Authentication failed for token submission [ token ]. Possible unexpected error? (Typical or expected login exceptions should extend from AuthenticationException).;ae new AuthenticationException(msg, t);if (log.isWarnEnabled())log.warn(msg, t);}try {notifyFailure(token, ae);} catch (Throwable t2) {if (log.isWarnEnabled()) {String msg Unable to send notification for failed authentication attempt - listener error?. Please check your AuthenticationListener implementation(s). Logging sending exception and propagating original AuthenticationException instead...;log.warn(msg, t2);}}throw ae;}log.debug(Authentication successful for token [{}]. Returned account [{}], token, info);notifySuccess(token, info);return info;} 通过方法doAuthenticate对认证Token进行认证通过notifySuccess、notifyFailure监听认证通过或失败的事件并调用注册的监听器 方法doAuthenticate的具体实现是在子类完成的如下 protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {assertRealmsConfigured();CollectionRealm realms getRealms();if (realms.size() 1) {return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);} else {return doMultiRealmAuthentication(realms, authenticationToken);}} 这里首先获取已注册的安全组件Realm其注册过程是在RealmSecurityManager初始化的过程中完成的对SecurityManager安全管理器的处理过程感兴趣可以参见Shiro框架Shiro SecurityManager安全管理器解析-CSDN博客 然后根据Realm的个数分别执行单Realm认证或多Realm认证这里已单Realm认证为例进行说明多Realm认证类似 1.2.1.1.1 单Realm认证 通过doSingleRealmAuthentication方法完成单Realm认证实现如下 protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {if (!realm.supports(token)) {String msg Realm [ realm ] does not support authentication token [ token ]. Please ensure that the appropriate Realm implementation is configured correctly or that the realm accepts AuthenticationTokens of this type.;throw new UnsupportedTokenException(msg);}AuthenticationInfo info realm.getAuthenticationInfo(token);if (info null) {String msg Realm [ realm ] was unable to find account data for the submitted AuthenticationToken [ token ].;throw new UnknownAccountException(msg);}return info;} 这里Reaml接口包含一整套的继承层次实现如下这里不过多展开解析 getAuthenticationInfo是在AuthenticatingRealm中完成的如下 public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {AuthenticationInfo info getCachedAuthenticationInfo(token);if (info null) {//otherwise not cached, perform the lookup:info doGetAuthenticationInfo(token);log.debug(Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo, info);if (token ! null info ! null) {cacheAuthenticationInfoIfPossible(token, info);}} else {log.debug(Using cached authentication info [{}] to perform credentials matching., info);}if (info ! null) {assertCredentialsMatch(token, info);} else {log.debug(No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null., token);}return info;} 这里首先获取AuthenticationInfo对象要么从缓存中获取要么通过引入的抽象方法doGetAuthenticationInfo获取交由应用层子类具体实现 获取到AuthenticationInfo后将其余用户录入的登录Token进行比对这部分具体是方法assertCredentialsMatch完成的具体如下 protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {CredentialsMatcher cm getCredentialsMatcher();if (cm ! null) {if (!cm.doCredentialsMatch(token, info)) {//not successful - throw an exception to indicate this:String msg Submitted credentials for token [ token ] did not match the expected credentials.;throw new IncorrectCredentialsException(msg);}} else {throw new AuthenticationException(A CredentialsMatcher must be configured in order to verify credentials during authentication. If you do not wish for credentials to be examined, you can configure an AllowAllCredentialsMatcher.class.getName() instance.);}} 这里获取了默认的匹配器SimpleCredentialsMatcher并调用doCredentialsMatch方法进行匹配匹配实现如下 public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {Object tokenCredentials getCredentials(token);Object accountCredentials getCredentials(info);return equals(tokenCredentials, accountCredentials);} 首先获取Credentials也即用户密码然后调用equals方法进行匹配如下通过字节流的方式进行比对主要是为了安全考虑系统处理时采用非明文形式。 protected boolean equals(Object tokenCredentials, Object accountCredentials) {if (log.isDebugEnabled()) {log.debug(Performing credentials equality check for tokenCredentials of type [ tokenCredentials.getClass().getName() and accountCredentials of type [ accountCredentials.getClass().getName() ]);}if (isByteSource(tokenCredentials) isByteSource(accountCredentials)) {if (log.isDebugEnabled()) {log.debug(Both credentials arguments can be easily converted to byte arrays. Performing array equals comparison);}byte[] tokenBytes toBytes(tokenCredentials);byte[] accountBytes toBytes(accountCredentials);return MessageDigest.isEqual(tokenBytes, accountBytes);} else {return accountCredentials.equals(tokenCredentials);}} 至此用户账号密码匹配完成匹配完成后会重新创建用户登录对象并更新用户状态等下面具体分析 1.2.1.2 认证通过后创建登录用户对象 认证通过后创建Subject的实现如下 protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) {SubjectContext context createSubjectContext();context.setAuthenticated(true);context.setAuthenticationToken(token);context.setAuthenticationInfo(info);if (existing ! null) {context.setSubject(existing);}return createSubject(context);}Overrideprotected SubjectContext createSubjectContext() {return new DefaultWebSubjectContext();} 这里创建了DefaultWebSubjectContext用户Subject创建其中设置了认证状态、认证Token、已认证信息然后调用createSubject方法继续进行构造如下 public Subject createSubject(SubjectContext subjectContext) {//create a copy so we dont modify the arguments backing map:SubjectContext context copy(subjectContext);//ensure that the context has a SecurityManager instance, and if not, add one:context ensureSecurityManager(context);//Resolve an associated Session (usually based on a referenced session ID), and place it in the context before//sending to the SubjectFactory. The SubjectFactory should not need to know how to acquire sessions as the//process is often environment specific - better to shield the SF from these details:context resolveSession(context);//Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first//if possible before handing off to the SubjectFactory:context resolvePrincipals(context);Subject subject doCreateSubject(context);//save this subject for future reference if necessary://(this is needed here in case rememberMe principals were resolved and they need to be stored in the//session, so we dont constantly rehydrate the rememberMe PrincipalCollection on every operation).//Added in 1.2:save(subject);return subject;} 如上创建过程包含了以下几部分分别进行分析; 1.2.1.2.1 复制SubjectContext 对subjectContext调用复制构造方法进行复制subjectContext底层通过backingMap保存上下文信息 public MapContext(MapString, Object map) {this();if (!CollectionUtils.isEmpty(map)) {this.backingMap.putAll(map);}} 1.2.1.2.2 对subjectContext设置securityManager 获取securityManager的顺序如下 首先从subjectContext中获取若无则从当前线程上下文中获取否则将当前securityManager设置到subjectContext中 protected SubjectContext ensureSecurityManager(SubjectContext context) {if (context.resolveSecurityManager() ! null) {log.trace(Context already contains a SecurityManager instance. Returning.);return context;}log.trace(No SecurityManager found in context. Adding self reference.);context.setSecurityManager(this);return context;} public SecurityManager resolveSecurityManager() {SecurityManager securityManager getSecurityManager();if (securityManager null) {if (log.isDebugEnabled()) {log.debug(No SecurityManager available in subject context map. Falling back to SecurityUtils.getSecurityManager() lookup.);}try {securityManager SecurityUtils.getSecurityManager();} catch (UnavailableSecurityManagerException e) {if (log.isDebugEnabled()) {log.debug(No SecurityManager available via SecurityUtils. Heuristics exhausted., e);}}}return securityManager;} 1.2.1.2.3 对subjectContext设置session 解析session方法如下其中session的解析顺序为 首先从subjectContext获取session判断是否已设置session见源码2否则通过subjectContext中保存的Subject对象获取关联的session见源码2其次通过sessionManager Session管理器获取见源码3Web服务中具体的Session管理器为ServletContainerSessionManager尝试从request请求中获取Servlet管理的Session见源码4 源码1  protected SubjectContext resolveSession(SubjectContext context) {if (context.resolveSession() ! null) {log.debug(Context already contains a session. Returning.);return context;}try {//Context couldnt resolve it directly, lets see if we can since we have direct access to //the session manager:Session session resolveContextSession(context);if (session ! null) {context.setSession(session);}} catch (InvalidSessionException e) {log.debug(Resolved SubjectContext context session is invalid. Ignoring and creating an anonymous (session-less) Subject instance., e);}return context;} 源码2  public Session resolveSession() {Session session getSession();if (session null) {//try the Subject if it exists:Subject existingSubject getSubject();if (existingSubject ! null) {session existingSubject.getSession(false);}}return session;} 源码3  protected Session resolveContextSession(SubjectContext context) throws InvalidSessionException {SessionKey key getSessionKey(context);if (key ! null) {return getSession(key);}return null;}public Session getSession(SessionKey key) throws SessionException {return this.sessionManager.getSession(key);} 源码4 ServletContainerSessionManager获取Session public Session getSession(SessionKey key) throws SessionException {if (!WebUtils.isHttp(key)) {String msg SessionKey must be an HTTP compatible implementation.;throw new IllegalArgumentException(msg);}HttpServletRequest request WebUtils.getHttpRequest(key);Session session null;HttpSession httpSession request.getSession(false);if (httpSession ! null) {session createSession(httpSession, request.getRemoteHost());}return session;} 1.2.1.2.4 对subjectContext设置Principals resolvePrincipals方法实现如下这里获取Principals的顺序为 先从SubjectContext中直接获取Principals见源码2否则通过SubjectContext中已认证的AuthenticationInfo获取见源码2其次通过SubjectContext中的Subject获取见源码2再次通过SubjectContext中的Session获取见源码2最后通过RememberMeManager中的Cookie中获取 源码1 protected SubjectContext resolvePrincipals(SubjectContext context) {PrincipalCollection principals context.resolvePrincipals();if (isEmpty(principals)) {log.trace(No identity (PrincipalCollection) found in the context. Looking for a remembered identity.);principals getRememberedIdentity(context);if (!isEmpty(principals)) {log.debug(Found remembered PrincipalCollection. Adding to the context to be used for subject construction by the SubjectFactory.);context.setPrincipals(principals);} else {log.trace(No remembered identity found. Returning original context.);}}return context;} 源码2从SubjectContext获取Principals public PrincipalCollection resolvePrincipals() {PrincipalCollection principals getPrincipals();if (isEmpty(principals)) {//check to see if they were just authenticated:AuthenticationInfo info getAuthenticationInfo();if (info ! null) {principals info.getPrincipals();}}if (isEmpty(principals)) {Subject subject getSubject();if (subject ! null) {principals subject.getPrincipals();}}if (isEmpty(principals)) {//try the session:Session session resolveSession();if (session ! null) {principals (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);}}return principals;} 1.2.1.2.5 根据subjectContext创建Subject 如下通过createSubject创建了WebDelegatingSubject对象 public Subject createSubject(SubjectContext context) {if (!(context instanceof WebSubjectContext)) {return super.createSubject(context);}WebSubjectContext wsc (WebSubjectContext) context;SecurityManager securityManager wsc.resolveSecurityManager();Session session wsc.resolveSession();boolean sessionEnabled wsc.isSessionCreationEnabled();PrincipalCollection principals wsc.resolvePrincipals();boolean authenticated wsc.resolveAuthenticated();String host wsc.resolveHost();ServletRequest request wsc.resolveServletRequest();ServletResponse response wsc.resolveServletResponse();return new WebDelegatingSubject(principals, authenticated, host, session, sessionEnabled,request, response, securityManager);} 1.2.1.2.6 保存Subject  Subject保存是通过DefaultSubjectDAO完成的 如下通过saveToSession方法保存Principals和认证状态到Session中 protected void saveToSession(Subject subject) {//performs merge logic, only updating the Subjects session if it does not match the current state:mergePrincipals(subject);mergeAuthenticationState(subject);} 这里在保存Principals的过程中如果Principals不为空且非Servlet Session的条件下这里会调用subject.getSession()方法创建shiro管理的native Session对象 subject.getSession()方法实现如下 public Session getSession() {return getSession(true);}public Session getSession(boolean create) {if (log.isTraceEnabled()) {log.trace(attempting to get session; create create ; session is null (this.session null) ; session has id (this.session ! null session.getId() ! null));}if (this.session null create) {//added in 1.2:if (!isSessionCreationEnabled()) {String msg Session creation has been disabled for the current subject. This exception indicates that there is either a programming error (using a session when it should never be used) or that Shiros configuration needs to be adjusted to allow Sessions to be created for the current Subject. See the DisabledSessionException.class.getName() JavaDoc for more.;throw new DisabledSessionException(msg);}log.trace(Starting session for host {}, getHost());SessionContext sessionContext createSessionContext();Session session this.securityManager.start(sessionContext);this.session decorate(session);}return this.session;} 如上通过securityManager的start方法创建Session对象start具体实现为  public Session start(SessionContext context) throws AuthorizationException {return this.sessionManager.start(context);} 这里又委托给了Session管理器完成session创建这里的Session管理器实现为AbstractNativeSessionManagerstart方法实现如下 public Session start(SessionContext context) {Session session createSession(context);applyGlobalSessionTimeout(session);onStart(session, context);notifyStart(session);//Dont expose the EIS-tier Session object to the client-tier:return createExposedSession(session, context);} 上述主要完成了以下几部分功能 1. 通过createSession方法创建SimpleSession对象其中包括了Session创建、Session保存到            sessionDAO中比如保存到内存中的子类MemorySessionDAO或者保存在数据库中的子类        EnterpriseCacheSessionDAO等SessionId生成等操作 图示sessionDAO的整体继承结构 2. Session全局超时时间配置默认超时时间为30min 3. onStart将SessionId存储到Cookie中如下     private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {if (currentId null) {String msg sessionId cannot be null when persisting for subsequent requests.;throw new IllegalArgumentException(msg);}Cookie template getSessionIdCookie();Cookie cookie new SimpleCookie(template);String idString currentId.toString();cookie.setValue(idString);cookie.saveTo(request, response);log.trace(Set session ID cookie for session with id {}, idString);} 至此用户登录认证过程完成了生成认证Token、通过Realm从应用中获取用户认证信息、用户认证Token匹配以及认证成功后创建用户Subject对象、保存Subject到Session、SessionId保存到Cookie等操作。
http://www.w-s-a.com/news/146342/

相关文章:

  • 能打开的网站你了解的彩票网站开发dadi163
  • 手机做网站价格优秀企业网站建设价格
  • 电商网站建设企业做网站的客户多吗
  • 有做思维图的网站吗西安建设市场诚信信息平台网站
  • 网站建设求职具备什么30岁学网站开发
  • 官方网站minecraft北京低价做网站
  • 网站建设报价兴田德润机械加工网络接单
  • 免费的推广网站安卓app制作平台
  • 长春火车站附近美食建设信用卡银行积分兑换商城网站
  • 网站提交网址如何备份wordpress网页
  • 龙腾盛世网站建设医院管理系统
  • 网站切换图片做背景怎么写外贸营销邮件主题一般怎么写
  • 基于html5的网站开发wordpress主题工具
  • php网站开发的成功经历公司网站现状
  • 软件发布网站源码中国企业公示信息网
  • flash 的网站网站型销售怎么做
  • 营销型网站单页网站的域名和密码
  • 建网站保定seo自动发布外链工具
  • 做公众号关注网站做课件用这15大网站
  • 怎么制作公司自己网站店铺设计软件手机版
  • 深圳网站关键词优化公司哪家好怎么选择锦州网站建设
  • 标准网站优势项目合作网站
  • 无人机东莞网站建设wordpress站群管理破解版
  • 深圳企业官网网站建设教育培训学校
  • 医疗网站建设及优化西安网站建设开发公司
  • 网站建设详细流程ydg wordpress theme
  • 湖北黄石域名注册网站建设编程网站项目做哪个比较好
  • 旺道网站排名优化咸阳建设网站
  • 建设一个类似淘宝的网站律师做推广宣传的网站
  • 东阳网站建设方案网站建设asp