[置顶] 自学-Shiro的身份认证-05
2016-12-15 17:20
225 查看
学习了前几节,大家可能只是对Shiro有个大概的了解,其实,Shiro的重点及难点都在后面的博客中,接下来的这节我们来探讨一下身份认证.
我们可以一起来看下身份认证流程,有个大概的思绪,在来一起写代码进行实现。
身份认证流程:
流程步骤(借鉴英文文档翻译):
1.首先调用Subject.login(token)进行登录,其会自动委托给Security Manager,调用之前必须通过SecurityUtils. setSecurityManager()设置;
2.SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;
3.Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实现;
4.Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证;
5.Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
流程大概就这个样子,其实可以用更加通俗易懂的语言来描述更好。这些流程看源码是最清楚的,所以我们可以针对源码进行走一下,然后理解起来会更加的清楚明了。
代码进行一一解释
如下:
1.首先进行登录:
4.Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证。
总而言之就是这样:
1.获取获取当前的 Subject. 调用 SecurityUtils.getSubject();
2.判断当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated() 。
3.若没有认证, 则把用户名和密码封装为 UsernamePasswordToken 对象。
4. 执行登录。调用 Subject 的login(token); 方法.
注:token指代是:AuthenticationToken
5.自定义 Realm 的方法, 从数据库中获取对应的记录,并对密码进行加密,来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo。
即:
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
实例结构:
实例代码:
LoginController.java:
自定义Realm:
MyRealm.java:
登录的页面:
login.jsp:
先让shiro/login进行匿名访问:
图形化界面;
现在我们来执行下这个操作:
首先进入登录页面:
http://localhost:8080/Shiro-03/login.jsp
根据代码,我们先输入一个正确的用户名和密码:zhao 123456 这时候会进入到对应的页面,假如我们在一次进行入到登录页面,随意输入个错误的密码,这时候还是可以登录上的,这个是为什么呢?
原因是:shiro的缓存起到了作用,这时候避免出现这样的现象我们直接在applicationContext.xml中配置一个logou的拦截器即可。
index.jsp:
applicationContext.xml:
这其中还有很多重点需要一一解释:
①:为什么自定义的[b]Realm 为什么直接继承AuthenticatingRealm呢?[/b]
②:[b]SimpleAuthenticationInfo 这个对象中的参数都指代什么呢?[/b]
③:shiro的密码怎么进行比对呢,怎么进行加密呢?
这些都到下一节进行详细的描述吧。
Ps:新手自学,哪里不对还望指出,谢谢。
我们可以一起来看下身份认证流程,有个大概的思绪,在来一起写代码进行实现。
身份认证流程:
流程步骤(借鉴英文文档翻译):
1.首先调用Subject.login(token)进行登录,其会自动委托给Security Manager,调用之前必须通过SecurityUtils. setSecurityManager()设置;
2.SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;
3.Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实现;
4.Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证;
5.Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
流程大概就这个样子,其实可以用更加通俗易懂的语言来描述更好。这些流程看源码是最清楚的,所以我们可以针对源码进行走一下,然后理解起来会更加的清楚明了。
代码进行一一解释
如下:
1.首先进行登录:
currentUser.login(token);2.SecurityManager一个大管家。
public void login(AuthenticationToken token) throws AuthenticationException { clearRunAsIdentitiesInternal(); Subject subject = securityManager.login(this, token); PrincipalCollection principals; String host = null; if (subject instanceof DelegatingSubject) { DelegatingSubject delegating = (DelegatingSubject) subject; //we have to do this in case there are assumed identities - we don't want to lose the 'real' principals: principals = delegating.principals; host = delegating.host; } else { principals = subject.getPrincipals(); } if (principals == null || principals.isEmpty()) { String msg = "Principals returned from securityManager.login( token ) returned a null or " + "empty value. This value must be non null and populated with one or more elements."; throw new IllegalStateException(msg); } this.principals = principals; this.authenticated = true; if (token instanceof HostAuthenticationToken) { host = ((HostAuthenticationToken) token).getHost(); } if (host != null) { this.host = host; } Session session = subject.getSession(false); if (session != null) { this.session = decorate(session); } else { this.session = null; } }3.Authenticator[b]核心的身份认证入口点。[/b]
/** * Delegates to the wrapped {@link org.apache.shiro.authc.Authenticator Authenticator} for authentication. */ public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException { return this.authenticator.authenticate(token); }
4.Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证。
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { assertRealmsConfigured(); Collection<Realm> realms = getRealms(); if (realms.size() == 1) {//单个 return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else {//多个 return doMultiRealmAuthentication(realms, authenticationToken); } }
总而言之就是这样:
1.获取获取当前的 Subject. 调用 SecurityUtils.getSubject();
2.判断当前的用户是否已经被认证. 即是否已经登录. 调用 Subject 的 isAuthenticated() 。
3.若没有认证, 则把用户名和密码封装为 UsernamePasswordToken 对象。
4. 执行登录。调用 Subject 的login(token); 方法.
注:token指代是:AuthenticationToken
5.自定义 Realm 的方法, 从数据库中获取对应的记录,并对密码进行加密,来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo。
即:
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
实例结构:
实例代码:
LoginController.java:
package com.yiyi.controller; import javax.servlet.http.HttpServletRequest; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * 登录的Controller * @author hanyiyi * */ @Controller @RequestMapping("/shiro") public class LoginController { /** * 登录方法 * @param request * @return */ @RequestMapping(value="/login",method=RequestMethod.POST) public String login(HttpServletRequest request){ //获取用户名和密码 String username = request.getParameter("username"); String password=request.getParameter("password"); // 使用SecurityUtils.getSubject();来获取当前的 Subject. Subject currentUser = SecurityUtils.getSubject(); //判断当前的用户是否已经被认证。 if(!currentUser.isAuthenticated()){ //若没被认证,则把用户名和密码封装为UsernamePasswordToken对象 UsernamePasswordToken token=new UsernamePasswordToken(username,password); token.setRememberMe(true); try { // 执行登录. currentUser.login(token); } // ... catch more exceptions here (maybe custom ones specific to your application? // 所有认证时异常的父类. catch (AuthenticationException ae) { //unexpected condition? error? System.out.println("登录失败---->"+ae.getMessage()); } } return "redirect:/index.jsp"; } }
自定义Realm:
MyRealm.java:
package com.yiyi.realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.AuthenticatingRealm; public class MyRealm extends AuthenticatingRealm{ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { //将AuthenticationToken对象转换成UsernamePasswordToken对象 UsernamePasswordToken upToken = (UsernamePasswordToken) token; //获取UsernamePasswordToken中的用户名 String username = upToken.getUsername(); //从数据库中查询 username 对应的用户记录 System.out.println("从数据库中查找"+username+"的信息"); //若用户的信息不存在,则抛出UnknownAccountException异常。 if("unknown".equals(username)){ throw new UnknownAccountException("用户不存在"); } //根据用户的信息进行反馈,则抛出LockedAccountException异常。 if("han".equals(username)){ throw new LockedAccountException("用户被锁定"); } //根据用户的信息来封装SimpleAuthenticationInfo对象。 //当前 realm 对象的 name String realmName = getName(); //认证的实体信息。 Object principal = username; //密码 Object credentials="123456"; SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(principal, credentials, realmName); return info; } }
登录的页面:
login.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>登录页面</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <h4>login page</h4> <form action="shiro/login" method="post"> username:<input type="text" name="username"> <br/><br/> password:<input type="password" name="password"><br/><br/> <input type="submit" value="提交"> </form> </body> </html>拦截器配置;
先让shiro/login进行匿名访问:
图形化界面;
现在我们来执行下这个操作:
首先进入登录页面:
http://localhost:8080/Shiro-03/login.jsp
根据代码,我们先输入一个正确的用户名和密码:zhao 123456 这时候会进入到对应的页面,假如我们在一次进行入到登录页面,随意输入个错误的密码,这时候还是可以登录上的,这个是为什么呢?
原因是:shiro的缓存起到了作用,这时候避免出现这样的现象我们直接在applicationContext.xml中配置一个logou的拦截器即可。
index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> index jsp <a href="shiro/logout">登出</a> </body> </html>
applicationContext.xml:
这其中还有很多重点需要一一解释:
①:为什么自定义的[b]Realm 为什么直接继承AuthenticatingRealm呢?[/b]
②:[b]SimpleAuthenticationInfo 这个对象中的参数都指代什么呢?[/b]
③:shiro的密码怎么进行比对呢,怎么进行加密呢?
这些都到下一节进行详细的描述吧。
Ps:新手自学,哪里不对还望指出,谢谢。
相关文章推荐
- 通过Shiro完成基础的身份认证
- Shiro学习随笔【二】身份认证
- Shiro学习随笔【二】身份认证
- [置顶] 自学-Shiro的MD5加密及更加严格的盐值加密-08
- [置顶] 自学-Shiro中多个Realms的另外一种配置方式-11
- [置顶] 自学-shiro注解-16
- Shiro学习总结(3)——Apache Shiro身份认证
- Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)
- Shiro学习随笔【二】身份认证
- Shiro学习随笔【二】身份认证
- shiro入门实战笔记(3)--身份认证
- Shiro框架身份认证(二)
- [置顶] 自学-Shiro中多Realm的配置-09
- 身份认证(shiro)
- [置顶] Shiro身份验证最详细的代码流转分析
- Shiro学习总结(3)——Apache Shiro身份认证
- 基于AOP实现权限管理:通过shiro认证身份和模拟授权认证
- Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)
- 【Shiro】Apache Shiro架构之身份认证(Authentication)
- Shiro学习随笔【二】身份认证