shiro中的reaml非常重要,所有的身份数据验证都在reaml中实现。可以把Realm看成DataSource,即安全数据源。
Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;
也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作。
下面以例子讲解其实现机制:
最开始用户、角色、权限都配置在shiro.ini配置文件中。
但实际项目中更多的是保存数据库中,因此reaml就应运而生,很好的帮我们做到了这一点。所有的身份认证都需经过它。
shiro配置文件中只需配置Reaml,用户和角色就不需配置了
我们需要给Shiro的SecurityManager注入自定义Realm
自定义Realm中只需继承抽象类AuthorizingRealm即可,重写身份认证和权限认证方法。
1 /** 2 * 3 */ 4 package com.hik.realm; 5 6 import java.sql.Connection; 7 import java.sql.SQLException; 8 9 import org.apache.shiro.authc.AuthenticationException; 10 import org.apache.shiro.authc.AuthenticationInfo; 11 import org.apache.shiro.authc.AuthenticationToken; 12 import org.apache.shiro.authc.SimpleAuthenticationInfo; 13 import org.apache.shiro.authz.AuthorizationInfo; 14 import org.apache.shiro.authz.SimpleAuthorizationInfo; 15 import org.apache.shiro.realm.AuthorizingRealm; 16 import org.apache.shiro.subject.PrincipalCollection; 17 18 import com.hik.dao.UserDao; 19 import com.hik.entity.User; 20 import com.hik.util.Dbutil; 21 22 /** 23 * @ClassName: MyRealm 24 * @Description: TODO 25 * @author jed 26 * @date 2017年7月22日下午4:33:44 27 * 28 */ 29 public class MyRealm extends AuthorizingRealm{ 30 31 private Dbutil dbutil=new Dbutil(); 32 private UserDao userDao = new UserDao(); 33 34 /** 35 *为当前登录的用户授予角色和权限 36 */ 37 @Override 38 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 39 String userName = (String) principals.getPrimaryPrincipal(); 40 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); 41 Connection con = null; 42 try { 43 con = dbutil.getConnection(); 44 authorizationInfo.setRoles(userDao.getRoles(con, userName)); 45 authorizationInfo.setStringPermissions(userDao.getPermissions(con, userName)); 46 } catch (Exception e) { 47 // TODO Auto-generated catch block 48 e.printStackTrace(); 49 }finally { 50 try { 51 con.close(); 52 } catch (SQLException e) { 53 // TODO Auto-generated catch block 54 e.printStackTrace(); 55 } 56 } 57 return authorizationInfo; 58 } 59 60 /** 61 * 验证当前登录的用户 62 */ 63 @Override 64 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 65 String userName = (String)token.getPrincipal(); 66 Connection con = null; 67 try { 68 con =dbutil.getConnection(); 69 User currentUser = userDao.getUserByUserName(con, userName); 70 if(currentUser!=null){ 71 AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(currentUser.getUserName(),currentUser.getPassword(),"myRealm"); 72 return authcInfo; 73 }else{ 74 return null; 75 } 76 } catch (Exception e) { 77 // TODO Auto-generated catch block 78 e.printStackTrace(); 79 }finally { 80 try { 81 con.close(); 82 } catch (SQLException e) { 83 // TODO Auto-generated catch block 84 e.printStackTrace(); 85 } 86 } 87 return null; 88 } 89 90 }
其中:
doGetAuthenticationInfo :身份认证(验证当前登录的用户)
doGetAuthorizationInfo :身份认证通过,该身份拥有的角色和权限。为当前登录的用户授予角色和权限。
当用户在拿到token(前台传过来用户名和密码生成)进行登录时,
登入代码
1 @Override 2 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 3 System.out.println("login dopost"); 4 log.info("login dopost"); 5 String userName = req.getParameter("userName"); 6 String password = req.getParameter("password"); 7 UsernamePasswordToken token = new UsernamePasswordToken(userName,password); 8 Subject subject = SecurityUtils.getSubject(); 9 Session session = subject.getSession(); 10 System.out.println("sessionId: "+session.getId()); 11 System.out.println("sessionHost: "+session.getHost()); 12 System.out.println("sessionTimeout: "+session.getTimeout()); 13 session.setAttribute("info", "session的数据"); 14 try{ 15 subject.login(token); 16 resp.sendRedirect("success.jsp"); //重定向 17 }catch(Exception e){ 18 log.error("登录失败", e); 19 req.setAttribute("errorInfo", "用户名或者密码错误"); 20 req.getRequestDispatcher("login.jsp").forward(req, resp);//请求转发 21 } 22 }
subject.login(token);
进入自定义realm(继承AuthorizingRealm)的doGetAuthenticationInfo方法和doGetAuthorizationInfo方法
doGetAuthenticationInfo :进行身份认证(验证当前登录的用户,token中获取的用户与后台数据库用户进行比对,存在则身份认证通过)。
一旦身份认证通过后,进入doGetAuthorizationInfo方法 则查询该身份拥有的角色及赋予的权限,并为当前登录的用户授予角色和权限。
整个过程完成,则实现了用户的身份认证,及角色和权限授予。
其实 Realm看成DataSource,即安全数据源。