spring项目框架的搭建(2):整合权限框架shiro

原创
2017/07/11 10:36
阅读数 86

结合《spring项目框架的搭建(1):基本搭建》代码,在此基础上完成shiro的整合。

整合前的准备

  1. 需要引入shiro相关的jar
  2. 需要一个realm给登录用户进行认证授权
  3. 添加shiro的配置文件,指定url的过滤规则
  4. web.xml配置shiro过滤
  5. 登录控制器调用
  • pom.xml内容追加一下几个依赖
 <!--shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>

<shiro.version>1.4.0</shiro.version> 表示shiro使用的版本号,这里使用的当前时间的最新版本。

  • 创建认证授权的Realm,这个类主要的作用是进行登录用户的身份认证和权限认证。

新建一个ShiroDbRealm.java类继承AuthorizingRealm,复写父类中的两个方法

doGetAuthorizationInfo,AuthenticationInfo;使用 @Component注解将对象交给容器管理。

伪代码如下:


    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()
        String currentUsername = (String)super.getAvailablePrincipal(principals);
        Admin admin=adminService.findByUserName(currentUsername);
        List<String> roles = new ArrayList<String>();//存放该用户具备的角色
        List<String> permissions = new ArrayList<String>();//存放该用户具备的权限

        //查询用户拥有的角色和对应的权限
        List<AdminRole> adminRolesList=adminRolesService.findByAdminId(admin.getId());
        if(adminRolesList!=null && adminRolesList.size()>0){
            Role role;
            for (AdminRole adminRoles:adminRolesList){
                role=roleService.get(Role.class,adminRoles.getRoleId());
                roles.add(role.getRoleName());
                RolePermission permission=roleService.findRolePermission(role.getId());
                if (permission!=null){
                    permissions.addAll(permission.getPermissionList());
                }
            }

        }



        //用来保存认证好的信息,
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if (admin.getIdentity()==1){
            info.addRole("admin");
            info.addStringPermission("*:*");
        }else {
            info.addRoles(roles);
            info.addStringPermissions(permissions);
        }

        return info;
    }

    /**
     * 认证回调函数,登录时调用.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
        Admin admin=adminService.findByUserName(token.getUsername());
        if (admin!=null){
            return new SimpleAuthenticationInfo(admin.getUsername(),admin.getPassword(),admin.getRealName());
        }else {
            return null;
        }

    }

AuthenticationInfo登录成后会执行此方法,但是需要在登录成功后的位置显示调用subject.login(token).

身份认证成功后会进入doGetAuthorizationInfo进行权限认证和存储。

  • 配置spring-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
    <description>Shiro安全配置</description>
    <!-- Shiro 安全管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="shiroDbRealm"/>
    </bean>

    <!-- Shiro 过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!--shiro 核心权限管理器 必须配置-->
        <property name="securityManager" ref="securityManager"/>
        <!--身份认证失败跳转的登录页面-->
        <property name="loginUrl" value="/admin/login"/>
        <!--认证成功跳转的指定页面-->
        <property name="successUrl" value="/admin/index"/>
        <!--权限认证失败跳转的指定页面-->
        <property name="unauthorizedUrl" value="/admin/unautho"/>
        <!--url 过滤规则-->
        <property name="filterChainDefinitions">
            <value>
                /admin/login = anon
                /admin/doLogin = anon
                /admin/logout = authc
                /admin/unautho=anon
                <!--/admin/** = [*:*]-->
            </value>
        </property>
    </bean>

    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
     
    <!-- 开启Shiro注解  AOP式方法级权限检查  -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true"/>
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

</beans>

同时在spring.xml中添加    <import resource="spring-shiro.xml"/>

  • 配置web.xml
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
      <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
      <param-name>targetFilterLifecycle</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/admin/*</url-pattern>
  </filter-mapping>
  • LoginController.java
    @RequestMapping(value = "doLogin",method = RequestMethod.POST)

    public ApiBean doLogin(String username, String password, Boolean rememberMe, HttpSession session, HttpServletRequest request){
        ApiBean apiBean;

        if (StrKit.notNull(username,password)) {
             //验证用户名密码是否正确
            JSONObject loginRes=adminService.login(username,password);

            if (loginRes.getBoolean("login")){
                Admin admin= (Admin) loginRes.get("admin");
                UsernamePasswordToken token = new UsernamePasswordToken(admin.getUsername(),admin.getPassword());
                Subject subject = SecurityUtils.getSubject();
                subject.login(token);
                apiBean= ApiBean.responseSuccess("登录成功");
            } else {
                apiBean= ApiBean.responseError(loginRes.getString("msg"));
            }



        } else {
            apiBean= ApiBean.responseError("用户名密码错误");
        }
        return apiBean;

    }

当subject.login(token)之后,会进入到自定义的realm中的AuthenticationInfo方法,该方法执行完成后会执行doGetAuthorizationInfo方法。在这里我显示的调用了service里的方法去验证用户名密码是否正确,在正确之后再将用户交由shiro进行二次身份核实和权限认证。

展开阅读全文
打赏
0
1 收藏
分享
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部