A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

每天笑呵呵

初级黑马

  • 黑马币:19

  • 帖子:5

  • 精华:0

本帖最后由 每天笑呵呵 于 2018-1-19 18:07 编辑

前言:权限管理是项目中不可缺少的一部分,它主要由两方面组成:认证和授权;它还有三个必备的实体类(5张表,类之间都是多对多的关系):User(用户)、Role(角色)、Permission(权限);它有两种主要控制方式:粗粒度URL级别的权限控制、细粒度的权限控制;这里将主要总结一下最近bos项目中的权限管理框架shiro的简单使用。


1.使用它首先就要导入jar包:(它有多个具体功能的jar包,这里直接使用全功能jar包)
                <shiro.version>1.2.2</shiro.version>
                <!-- 权限控制 框架 -->
                <dependency>
                        <groupId>org.apache.shiro</groupId>
                        <artifactId>shiro-all</artifactId>
                        <version>${shiro.version}</version>
                </dependency>
2.shiro这个框架从你开始访问项目的时候就要进行权限控制,因此,便可以通过一个过滤器来实现。
web.xml中配置:
                <!-- shiro的Filter  -->
                filter的名字不能乱起,必须是这个因为这个filter会拿这个名字去核心配置文件中找同名的bean
        <filter>
                <!-- 去spring配置文件中寻找同名bean  -->
                <filter-name>shiroFilter</filter-name>
                <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
        <filter-mapping>
                <filter-name>shiroFilter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>

3.当过滤器拦截请求后,就可以进行权限控制了,第一步就是拿着自己过滤器的名字去spring核心配置文件中查找同名的bean
applicationContext-shiro.xml配置:
         <!-- shiro filter配置 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
                <!-- shiro 的核心安全接口 -->
                <property name="securityManager" ref="securityManager" />
                <!-- 要求登录时的链接 -->
                <property name="loginUrl" value="/login.jsp" />
                <!-- 登陆成功后要跳转的连接 -->
                <property name="successUrl" value="/index.jsp" />
                <!-- 未授权时要跳转的连接 -->
                <property name="unauthorizedUrl" value="/unauthorized.jsp" />
                <!-- shiro 连接约束配置 -->
                <!-- url级别权限权限控制 -->
                <property name="filterChainDefinitions">
                        <value>
                        【anon是不验证也不拦截,一个*是指后面可以添加参数?username=...】
                        【authc:认证后可以访问;perms:需要特定权限才能访问;roles:需要特定角色才能访问;
                        user:需要特定用户才能访问;port:需要特定端口才能访问;reset:根据指定HTTP请求访问才能访问】
                                【这是登录界面所以要放行】
                                /login.jsp*=anon
                                【之所以放行这个action,是因为这个action是认证前访问,如果不放行,表单提交不了,又会回到登陆界面】
                                /user_login.action*=anon
                                【这个是登录页面验证码的jsp】
                                /validatecode.jsp*=anon
                                /unauthorized.jsp*=anon
                                /css/*=anon
                                /js/*=anon
                                /images/*=anon
                                /json/*=anon
                                【这是表示webService的路径也不必拦截,因为webService在web.xml中配置这个路径,两个*表示当前目录下所有文件文件夹】
                                /services/** = anon
                                /easyuidemo/*=anon
                               【粗粒度的权限控制】
                                【访问这个页面需要特定权限】
                                /page_base_staff.action*=perms["staff"]
                                【访问这个页面需要特定角色】
                                /page_base_region.action*=roles["base"]

                                /*=authc
                        </value>
                </property>
        </bean>

4.讲到这配置文件还没有配置完,先上一张图,说一下,再说一下前言中涉及的东西。

上图显示了shiro的三大组件,框架的执行流程:应用程序---Subject(框架管理的用户)----SecurityManager(底层调用,它是框架的核心)----Realm(程序与权限控制数据之间的连接器,读取安全数据(数据表、文件、网络))
后面的所有操作都是围绕着这个流程进行的,因此它是重中之重,必须掌握。
5.当你访问这个工程的时候,正如上面配置文件中设置一样,默认将页面导向login.html,因此只有登录才能够访问工程,账号密码输入,进入UserAction的login方法,
        (1)将用户账号密码给Subject:

        @Action(value = "user_login", results = {
                        @Result(name = "login", type = "redirect", location = "login.html"),
                        @Result(name = "success", type = "redirect", location = "index.html") })
        public String login() {
                // 用户名和密码 都保存在model中
                // 基于shiro实现登录
                Subject subject = SecurityUtils.getSubject();

                // 用户名和密码信息
                AuthenticationToken token = new UsernamePasswordToken(
                                model.getUsername(), model.getPassword());
                try {
                        【这一步,将代码保存你登录输入的账号密码,底层调用了上图中的SecurityManager,这个类就在配置文件里,下面将添加这个bean
                        subject.login(token);
                        // 登录成功
                        // 将用户信息 保存到 Session
                        return SUCCESS;
                } catch (AuthenticationException e) {
                        // 登录失败
                        e.printStackTrace();
                        return LOGIN;
                }
        }

6.配置文件增加一个框架底层核心类,这个类拿到账号密码后就会通过Realm类来查询数据库,因此创建一个名为BosRealm的类
配置文件加上一段:
        <!-- 安全管理器 -->
        <bean id="securityManager"
                class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
                <property name="realm" ref="bosRealm" />
        </bean>

        <!-- 后处理器 -->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

编写Realm类:只需要继承Realm的子类AuthorizingRealm,这是一个抽象类,里面包含认证和授权方法,都是框架底层默认调用的。
        【加@service是为了让spring扫描到这个类,将这个类注入到安全管理器的bean标签中】
        @Service("bosRealm")【这写了名字,那么在配置文件属性注入时,ref写这个名字即可】
        public class BosRealm extends AuthorizingRealm {

                @Autowired
                private UserService userService;

                @Autowired
                private RoleService roleService;
               
                @Autowired
                private PermissionService permissionService;

                @Override
                // 授权...
                protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
                        System.out.println("shiro 授权管理...");
                        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
                        // 根据当前登录用户 查询对应角色和权限
                        Subject subject = SecurityUtils.getSubject();
                        User user = (User) subject.getPrincipal();
                        // 调用业务层,查询角色
                        List<Role> roles = roleService.findByUser(user);
                        for (Role role : roles) {
                                authorizationInfo.addRole(role.getKeyword());
                        }
                        // 调用业务层,查询权限
                        List<Permission> permissions = permissionService.findByUser(user);
                        for (Permission permission : permissions) {
                                authorizationInfo.addStringPermission(permission.getKeyword());
                        }
                      //返回的就是权限信息
                        return authorizationInfo;
                }

                @Override
                // 认证...
                protected AuthenticationInfo doGetAuthenticationInfo(
                                AuthenticationToken token) throws AuthenticationException {
                        System.out.println("shiro 认证管理... ");
                        【这个token已经有了你登录时输入的的账号密码】
                        // 转换token
                        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

                        // 根据用户名 查询 用户信息,因为如果登录成功,需要将查询到的完整用户信息保存到Subject对象中,以后认证的时候需要用到uid
                        User user = userService.findByUsername(usernamePasswordToken
                                        .getUsername());
                        if (user == null) {
                               // 用户名不存在
                                // 参数一: 期望登录后,保存在Subject中信息
                                // 参数二: 如果返回为null 说明用户不存在,会报用户名不存在
异常org.apache.shiro.authc.UnknownAccountException
                                // 参数三 :realm名称
                                return null;
                        } else {
                               // 用户名存在
                                // 当返回用户密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
                                // 如果密码一致 登录成功, 如果密码不一致 报密码错误
异常org.apache.shiro.authc.lncorrectCredentialsException
                                return new SimpleAuthenticationInfo(user, user.getPassword(),
                                                getName());
                        }

                }

        }
7.上面配置文件中被标记为黑底白字的就是粗粒度url级别控制,如果要细粒度方法级别控制,需要配置文件增加shiro注解扫描和在需要权限的地方加上权限注解配置文件加上:
        <!-- 开启shiro注解模式 -->
        <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>

同时配置事务的配置文件也要修改这句,目的是使用cglab动态代理
        <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
方法上的注解:
        @RequiresPermission("权限名"):需要特点权限才能访问
        @RequiresRoles("角色名"):需要特点角色才能访问

1 个回复

倒序浏览
感谢老师的分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马