Shiro实现(一): SSM整合笔记实现登录,授权功能

来源:互联网 发布:时时彩断组软件 编辑:程序博客网 时间:2024/06/08 04:20

开篇

  1. 本项目已经上传)github,建议对照代码理解
  2. 本篇主要讲Shiro框架与SSM框架结合,实现登录和授权功能
  3. 利用spring 的aop切面思想,很简单得融合Shiro权限框架
  4. 代码

需要明白两个点:
1. 通过Subject.login() 登录成功后,用户信息就会保存在安全管理器上,也就是 SecurityManager。就可以在程序任何地方获取到该用户对象。
2. 在重写拦截器两个方法是重点,在登录的时候就需要把授权信息也存到安全管理器上,所以登录成功后,所有判断权限都不需要在业务逻辑上做判断,shiro框架已经帮你拦截并判断好。

1. jar包

shiro有很多种类型的包,用途有web的,非web的等,*-all 代表所有都在里面
shiro-all.jar

2.配置

其实shiro权限控制就是通过拦截器来进行判断用户权限的,因此shiro拦截器的配置跟springMVC的拦截器配置是类似的。

第一步

尽然是通过aop来使用shiro,那就需要在web.xml里添加一个shiro的拦截器。

ps:这个shiro拦截器是如何加载的呢? 因为这个项目shiro与spring整合了,所有运行项目的时候,spring监听器会去寻找并加载shiro拦截器

 <!-- Spring监听器 -->  <listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  </listener>

shiro拦截器配置如下:

<!-- 配置由Spring提供的过滤器,用于整合shiro框架 -->  <!-- 在项目启动的过程中,当前过滤器会从Spring工厂中提取同名对象 -->  <filter>    <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>

第二步

类似springmvc一样,需要写一个配置文件来配置拦截器。
在shiro配置文件中,有两种类型。
- ini配置文件 (很多博客教程上都是使用这种配置方式。)
- xml配置文件 (这次项目使用这种配置方式)

首先创建shiro-context.xml

ps: 很简单,就相当于spring的配置文件一样,因为shiro是跟spring很好结合的。
下面会慢慢解释这个配置文件

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <property name="securityManager" ref="securityManager" /> <!--加载管理器-->        <property name="loginUrl" value="/user/login" />    <!--没有登录的时候,跳转到这个页面-->        <property name="unauthorizedUrl" value="/user/nopermission" /> <!--当没有权限的时候,跳转到这个url-->        <property name="filterChainDefinitions">            <value>                /user/login = anon <!--可以不需要登录-->                /user/readName = authc, perms[/readName]  <!-- perms 表示需要该权限才能访问的页面 -->                /user/readData = authc, perms[/readData]                /user/* = authc <!-- authc 表示需要认证才能访问的页面 -->            </value>        </property>    </bean>    <!-- 自定义Realm -->    <bean id="myShiroRealm" class="com.Shiro.MyShiroReaml">        <!-- businessManager 用来实现用户名密码的查询 -->        <property name="shiroService" ref="accountService" />    </bean>    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">        <!-- 注入realm -->        <property name="realm" ref="myShiroRealm"/>    </bean>    <!--声明一个Service 注入到自定义Realm-->    <bean id="accountService" class="com.Service.Impl.ShiroServiceImpl"/>    <!-- <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">         <property name="cacheManager" ref="cacheManager" /> </bean> --></beans>
  1. 拦截器需要加载一个安全管理器,SecurityManager 是整个shiro框架的核心
    <property name="securityManager" ref="securityManager" /> <!--加载管理器-->
  1. 拦截url,这里就是配置拦截url。anon.authc.这些名词其实就是shiro已经写好的拦截器,只需要调用可以了。在如果权限不够,则会跳转到指定的url
  <property name="filterChainDefinitions">            <value>                /user/login = anon <!--可以不需要登录-->                /user/readName = authc, perms[/readName]  <!-- perms 表示需要该权限才能访问的页面 -->                /user/readData = authc, perms[/readData]                /user/* = authc <!-- authc 表示需要认证才能访问的页面 -->            </value>        </property>

过滤器列表:

208783.jpg

第三步 拦截后,对用户进行验证

当你拦截器设置好了,可以成功拦截用户的操作,然后我们需要对用户进行权限验证。所以我们需要继承shiro的AuthorizingRealm拦截器,重写两个方法。
- 重写doGetAuthenticationInfo方法是:登录验证,当需要登录的时候,就会调用该方法进行验证。
- 重写doGetAuthorizationInfo方法:这个是授权验证,与上面的过滤器相结合。

思路如下:
- 登录验证: 根据账号从数据库获取账号密码进行比较,如果一致则登录成功,就会保存到,否则登录失败
- 授权验证:在登录成功后,根据用户id获取到该用户的权限,并把权限保存在安全管理器之中,当用户访问的时候,会从管理器中判断该用户是否有权限去访问该url。
代码如下:

public class MyShiroReaml extends AuthorizingRealm {    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {        /**         *          * 流程         * 1.根据用户user->2.获取角色id->3.根据角色id获取权限permission         */        //方法一:获得user对象        User user=(User)pc.getPrimaryPrincipal();        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        //获取permission        if(user!=null) {            List<Permission> permissionsByUser = shiroService.getPermissionsByUser(user);            if (permissionsByUser.size()!=0) {                for (Permission p: permissionsByUser) {                    info.addStringPermission(p.getUrl());                }                return info;            }        }        //方法二: 从subject管理器里获取user//      Subject subject = SecurityUtils.getSubject();//      User _user = (User) subject.getPrincipal();//      System.out.println("subject"+_user.getUsername());        return null;    }    // 认证方法    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        System.out.println("进来验证了");        //验证账号密码        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;        System.out.println("1:"+token.getUsername());        User user = shiroService.getUserByUserName(token.getUsername());        System.out.println("2");        if(user==null){            return null;        }        //最后的比对需要交给安全管理器        //三个参数进行初步的简单认证信息对象的包装        AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getSimpleName());        return info;    }    private ShiroService shiroService;    public ShiroService getShiroService() {        return shiroService;    }    public void setShiroService(ShiroService shiroService) {        this.shiroService = shiroService;    }}

第四步

shrio的基本配置已经完成了,接下来是基础代码块了, 也许还有很多疑问,没关系。下载代码下来看看,就明白了

Controller层

1.登录代码块

 @RequestMapping(value = "/login")    public String Login(String username, String password, HttpSession session, Model model){        if(username==null){            model.addAttribute("message", "账号不为空");            return "login";        }        //主体,当前状态为没有认证的状态“未认证”        Subject subject = SecurityUtils.getSubject();        // 登录后存放进shiro token        UsernamePasswordToken token=new UsernamePasswordToken(username,password);        User user;        //登录方法(认证是否通过)        //使用subject调用securityManager,安全管理器调用Realm        try {            //利用异常操作            //需要开始调用到Realm中            System.out.println("========================================");            System.out.println("1、进入认证方法");            subject.login(token);            user = (User)subject.getPrincipal();            session.setAttribute("user",subject);            model.addAttribute("message", "登录完成");            System.out.println("登录完成");        } catch (UnknownAccountException e) {            model.addAttribute("message", "账号密码不正确");            return "index";        }        return "test";    }
  1. 权限代码块
shiro已经帮我们验证了,所以我们只需要写基本业务逻辑就可以,不需要再写权限验证代码了 @RequestMapping("/readName")    public String readName(HttpSession session){        return "name";    }    @RequestMapping("/readData")    public String readData(){        return "data";    }    @RequestMapping("/nopermission")    public String noPermission(){        return "error";    }

Service 层

public class ShiroServiceImpl implements ShiroService {    @Autowired    private ShiroDao shiroDao;    public User getUserByUserName(String username) {        //根据账号获取账号密码        User userByUserName = shiroDao.getUserByUserName(username);        return userByUserName;    }    public List<Permission> getPermissionsByUser(User user) {        //获取到用户角色userRole        List<Integer> roleId = shiroDao.getUserRoleByUserId(user.getId());        List<Permission> perArrary = new ArrayList<>();        if (roleId!=null&&roleId.size()!=0) {            //根据roleid获取peimission            for (Integer i : roleId) {                perArrary.addAll(shiroDao.getPermissionsByRoleId(i));            }        }        System.out.println(perArrary);        return perArrary;    }}

POJO层

public class Permission {    private int id;    private String token;    /**资源url**/    private String url;    /**权限说明**/    private String description;    /**所属角色编号**/    private int roleId;    }public class Role {    private int id;    /**角色**/    private String role;    /**说明**/    private String description;    }public class User {    private int id;    private String account;    private String password;}

第5步 数据库表的建立

数据表已经附加到代码上传到github
数据库中添加一条用户、角色、以及权限数据,并且在关联表中添加一条关联数据
- Permission 权限表

Permission.png

  • 角色管理表

角色管理表.png

  • 用户表

用户表.png

  • 用户角色对照表

用户角色对照表.png

总结

  1. Shiro框架 与spring结合,对原有的代码块改变很少。完美得实现了AOP思想
  2. Shiro的功能很强大,该项目实现了登录已经授权的基本功能,接下来还会有单点登录,缓存机制,密码加密等功能的演示。
  3. 代码已放到github上,可以clone下来细看。
  4. 代码
原创粉丝点击