实战-Shiro安全框架(一)认证

  Shiro是一个很不错的安全权限框架,可以完成认证、授权、加密、会话管理、缓存等。既能用于javase,也可以用于JavaEE中。这里,笔者以Javaee中为例,讲解一下shiro的第一部分--认证。

  认证,通俗的说,就是我们web系统的登陆。使用shiro框架后,就不用我们向之前那样写较多的对账号密码的逻辑判断校验了,直接调用shiro的相关api即可轻松完成认证。当然,这里面的底层也离不开我们常规的账号密码逻辑判断校验,只是shiro对它们进行了更好地封装与优化。

  首先,我们来了解一下shiro的框架的架构,这样有助于理解shiro框架运转流程。从shiro内部来看,如图所示

实战-Shiro安全框架(一)认证_第1张图片

从架构图中可以看出,shiro最为核心的是security manager(安全管理器),学过springmvc的话,可以理解它为DispatcherServlet的作用。所有与安全有关的操作,都会委托到它这里来。而subject可以理解shiro的门面,与外部代码直接交互的对象,但真正起作用的是它背后的security manager。subject代表的是当前“用户”,这里的用户可以指真正的用户,也可以是机器人、网络爬虫等一切与当前应用交互的对象。security manager里面包含三个很核心的组成部位,一个是Authenticator(认证器)负责subject认证。另一个是Authorizer(授权器)负责控制subject对资源的访问权限。最后一个是Realm我们可以理解为安全实体数据源,即认证器和授权器进行认证授权时,都会去Realm获取数据。至于其他部件,笔者这里不作讲述,因为,缓存、会话管理等这些在实际开发,有其他方案可以更好的解决,而不采取shiro提供的。

  现在我们来使用shiro的认证来实现我们web系统的登陆功能。准备如下:

1.数据表

实战-Shiro安全框架(一)认证_第2张图片

2.ssm整合的web工程

实战-Shiro安全框架(一)认证_第3张图片

3.shiro jar包引入

实战-Shiro安全框架(一)认证_第4张图片

现在开始具体实现。首先,需要在web.xml配置shiro filter拦截器,用来拦截需要安全控制的URL,然后进行相应的控制。这里笔者顺便提醒一下,shiro filter优先于springmvc的拦截器。

   
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
        
            targetFilterLifecycle
            true
        
    

    
        shiroFilter
        /*
    

第二部,配置shiro核心配置文件applicationContext-shiro.xml。配置文件如下




    
    
         
    
        
        
        
        
        	
    			
    		
        
        
        
    

    
         
    
        
        
         
    
    
    
//认证策略
    	

    		
    	
    

    
         
    
    	
    		
//md5加密
    			
//加密次数
    			
    		
    	
    
   
    
    
           
    

    
         
    
    
        
    

    
         
    
        
        
        
        
        
        
        
            
                /showLogin.action = anon
                /login.action = anon
                /logout.action = logout
                
                /user.action = roles[user]
                /admin.action = roles[admin]
                /list.action = user
                # everything else requires authentication:
                /** = authc
            
        
    


具体配置,笔者已经在注释写的听清楚了,这里概括一下,这里的配置文件,就是要配置最为核心的security manager以及shiro filter。这里涉及到很多一些shiro的配置细节,比如认证策略、url匹配模式以及shiro的过滤器等,已经在配置文件的注释作了介绍,这里不再展开叙述。

到这里,shiro整合到我们的web应用已经完成了。这里讲一下shiro的认证大致流程,前台页面传递用户名和密码到后台controller,后台利用shiro得到subject,subject调用login方法进行登录。而subject会委托给security manager,security manager委托给Authenticator,Authenticator 可能会委托给相应的AuthenticationStrategy(认证策略) 进行多 Realm 身份验证。Authenticator 会把相应的token传入Realm获取当前用户的认证信息比进行匹配认证。

具体代码如下

@Controller
public class UserController {
    @RequestMapping("/login.action")
    public String login(@RequestParam("username")String loginName,
                        @RequestParam("password")String password){
//利用SecurityUtils得到当前用户
        Subject subject = SecurityUtils.getSubject();
//如果当前用户未认证过
        if (!subject.isAuthenticated()){
//组装token
            UsernamePasswordToken token = new UsernamePasswordToken(loginName,password,true);
//设置是否记住我
            token.setRememberMe(true);
            try {
                System.out.println("开始执行登陆");
//调用login方法进行登录
//将会委托给security manager,到realm进行具体的认证匹配
                subject.login(token);
            }catch (AuthenticationException ae){
                ae.printStackTrace();
                System.out.println("登录失败: " + ae.getMessage());
                return "login";
            }
        }
//登录成功,跳转成功页面
        return "list";
    }
}

realm的实现,只需要继承AuthorizingRealm即可。实现两个方法

public class ShiroRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        return null;
    }
}

具体认证实现如下

public class ShiroRealm extends AuthorizingRealm {
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//传入的token转回UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
//getPrincipal方法可以获取到唯一身份标识。比如用户名、邮箱等
        String principal = (String) upToken.getPrincipal();
//根据传入的唯一身份标识--用户名到数据库查询该用户信息
        SysUser user = userService.getUserByLoginNmae(principal);
//唯一身份标识也可以使用查询出来的实体对象
        //Object principal = user;
        if (user == null){
            throw new UnknownAccountException("账户不存在!");
        }
//取出从数据库查出来的密码
        Object credentials = user.getPassword();
//盐值加密。
//我们之前shiro的配置文件中配置了加密方式为MD5,但是假如有些人的密码是相同的,则加密后的密码
//就会一样的,为了提高安全性,使用盐值加密,这样,即使密码相同,加密后的密码也会不一样,当然参数
//要选择唯一的,比如principal就最好。
        ByteSource credentialsSalt = ByteSource.Util.bytes(principal);
//最好构建SimpleAuthenticationInfo对象返回即可
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,credentials,credentialsSalt,getName());
        return info;
    }
 @Autowired
    private UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

补充一点,shiro提供异常有如下所示,可根据具体情况而抛出。

实战-Shiro安全框架(一)认证_第5张图片

到这里,认证就基本实现了。最后总结一下认证步骤,配置shiro文件以及web.xm的lshiro拦截器(这一步是只要是想要使用shiro都要做的),编写realm类,调用login方法。

关于shiro的权限控制,笔者将在下一篇中详细介绍。

你可能感兴趣的:(shiro)