shiro小而美的安全框架

最近项目需要利用shiro来进行权限管理实现,本人也是第一次接触,写的不好还请见谅。
首先shiro是一个java的安全框架,能够帮我们实现登录认证,权限认证等其他功能,如rememberMe。
主要关注点如下:

  1. Subject:可以看成当前用户
  2. Token:令牌,包含当前用户利用form表单提交的用户名和密码信息
  3. Authentication:身份认证,可以理解成当前用户的用户名和密码验证
  4. Authorization:权限认证,可以理解成当前用户访问某个资源时的权限判断
  5. Realm:安全数据源,可以理解成当前用户相关的身份信息及权限相关信息(暂时可以这么理解)

整体结构大致如下:

How
有关shiro的dependencies大致如下:(特别注明:这里页面模板引擎用的是Thymeleaf而不是jsp)

        
        <dependency>  
            <groupId>org.apache.shirogroupId>  
            <artifactId>shiro-coreartifactId>  
            <version>1.2.2version>  
        dependency> 
        
        <dependency>  
        <groupId>org.apache.shirogroupId>  
            <artifactId>shiro-webartifactId>  
            <version>1.2.2version>  
        dependency>
        
         <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>1.2.2version>
        dependency>
        
        
        <dependency>
            <groupId>com.github.theborakompanionigroupId>
            <artifactId>thymeleaf-extras-shiroartifactId>
            <version>2.0.0version>
        dependency>
  dependencies>

增加完shiro相关依赖就需要我们在spring的配置文件中增加如下配置:

        
        <bean id="userRealm" class="com.myjava.realm.UserRealm">
            <property name="credentialsMatcher" ref="credentialsMatcher">property>
        bean>
        
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="userRealm"/>
            
            <property name="sessionManager" ref="defaultWebSessionManager"/>
            <property name="rememberMeManager" ref="remembermeManager"/>
        bean>
        
        <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            
            <property name="hashAlgorithmName" value="md5"/>
            <property name="hashIterations" value="2">property>
        bean>

          
        <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
            <property name="staticMethod"   
                value="org.apache.shiro.SecurityUtils.setSecurityManager"/>  
            <property name="arguments" ref="securityManager"/>  
        bean>  
          
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  

先从登录开始,其实shiro中的默认的过滤器就已经帮助我们实现从登录(login)到身份认证(authentication),我们只需要在shiro的配置文件中配置好过滤器即可,但是这里为了更清晰了解这个过程,先自己写一个登录的Controller,如下:

@RequestMapping("/login")
public String login(User user, ModelMap mm , HttpSession session,HttpServletResponse response,RedirectAttributes attrs ) {
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername() , user.getPassword()) ;
        //rememberMe
        token.setRememberMe(true);
        //获取主体
        Subject subject = SecurityUtils.getSubject() ;
        try {
            //登录
            subject.login(token);
        } catch (AuthenticationException e) {
            System.out.println("---------------用户名或者密码错误-------------------");
            attrs.addFlashAttribute("msg","用户名或密码错误") ;
            e.printStackTrace();
            return "redirect:toLogin.action" ;
        }
        subject.getSession().setAttribute("user", userService.getByUserName(user.getUsername()));
        return "redirect:index.action";
    }

由于用户输入的username及password需要利用数据库中的信息进行对比,这必然涉及到数据库的交互,而shiro将这个交互封装到Realm中,即shiro通过Realm获取信息,而realm才真正从数据库中获取信息。所以我们需要自定义一个Realm,如下:

public class UserRealm extends AuthorizingRealm{
    @Autowired
    private RoleService roleService  ;
    @Autowired
    private UserService userService ;
    @Autowired
    private PermissionService permissionService ;
    //保存当前用户的授权信息
    private SimpleAuthorizationInfo info = new SimpleAuthorizationInfo() ;
    /**
     * 获取用户授权信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        /**
         * 将用户角色信息放入SimplAuthorizationInfo
         */
        info.setRoles(this.addRoles(username));
        /**
         * 将用户权限信息放入SimpleAuthorizationInfo中
         */
        info.setStringPermissions(this.addPermissions(username));

        return info;
    }
    /**
     * 获取用户身份信息
     * CredentialsMatcher会进行密码验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        //用户输入的用户名和密码
        String username = (String) token.getPrincipal() ;
        //数据库查找的user
        User accountUser = userService.getByUserName(username) ;
        //验证
        if(accountUser == null) throw new UnknownAccountException() ;
        //会调用credentialMatcher进行密码验证
        return new SimpleAuthenticationInfo(accountUser.getUsername(),accountUser.getPassword(),new SimpleByteSource(accountUser.getSalt()),getName());
    }

注意以上override的两个方法,doGetAuthenticationInfo是获取用户认证信息,doGetAuthorizationInfo是获取用户权限信息。
执行流程如下:
1. 将form表单传来的用户信息封装到UsernamePasswordToken 中。
2. 通过Subject subject = SecurityUtils.getSubject() ; 获取subject主体。
3. 执行登录行为subject.login(token); 之后委托给securityManager执行真正的login操作,也是说securityManager才是真正的核心。
4. shiro会自动获取配置好的Realm(可以有多个),如上面自定义的UserRealm,在Realm中获取当前username对应的用户相关信息(如username,password……)
5. 内部会调用之前配置好的HashedCredentialsMatcher密码匹配器进行密码验证(期间会根据指定的算法进行密码的加密),如果匹配失败则会抛出IncorrectCredentialsException。

登录成功后subject.isAuthenticated()就会return true.至此登录的雏形就完成了。

未完待续……

你可能感兴趣的:(shiro学习笔记)