shiro小而美的安全框架

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

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

整体结构大致如下:

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

        <!-- shiro -->
        <dependency>  
            <groupId>org.apache.shiro</groupId>  
            <artifactId>shiro-core</artifactId>  
            <version>1.2.2</version>  
        </dependency> 
        <!-- shiro -web -->
        <dependency>  
        <groupId>org.apache.shiro</groupId>  
            <artifactId>shiro-web</artifactId>  
            <version>1.2.2</version>  
        </dependency>
        <!-- shiro-spring -->
         <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <!-- 以下为thymeleaf权限标签,如果不是用Thymeleaf请忽略 -->
        <!-- shiro-thymeleaf-tag -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
  </dependencies>

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

        <!-- 自定义的Realm -->
        <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"/>
            <!-- 会话管理及rememberMe,可以等到需要时再配置 -->
            <property name="sessionManager" ref="defaultWebSessionManager"/>
            <property name="rememberMeManager" ref="remembermeManager"/>
        </bean>
        <!-- 密码匹配器 -->
        <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            <!-- 指定加密算法,此处是MD5 -->
            <property name="hashAlgorithmName" value="md5"/>
            <property name="hashIterations" value="2"></property>
        </bean>

        <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->  
        <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
            <property name="staticMethod"   
                value="org.apache.shiro.SecurityUtils.setSecurityManager"/>  
            <property name="arguments" ref="securityManager"/>  
        </bean>  
        <!-- Shiro生命周期处理器-->  
        <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.至此登录的雏形就完成了。

未完待续……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值