API文档:Apache Shiro 1.9.0 API

核心三个对象

  • Subject 用户
  • SecurityManager 管理所有用户
  • Realm 连接数据

    第一步:引入依赖

    1. <!--shiro权限认证框架-->
    2. <dependency>
    3. <groupId>org.apache.shiro</groupId>
    4. <artifactId>shiro-spring-boot-web-starter</artifactId>
    5. <version>1.9.0</version>
    6. </dependency>

    第二步、shiro配置(java)

    1.创建UserRealm

    ```java package com.tj.reggie.config;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.tj.reggie.entity.Users; import com.tj.reggie.service.UsersService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired;

//自定义的UserRealm public class UserRealm extends AuthorizingRealm { @Autowired //自动加载业务层接口 private UsersService usersService;

  1. //授权
  2. @Override
  3. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
  4. System.out.println("执行了授权AuthorizationInfo");
  5. //获取当前登录的用户对象
  6. Subject subject = SecurityUtils.getSubject();
  7. Long id = (Long) subject.getPrincipal(); //获取用户的id

// //根据用户的id查询当前用户的角色 // Set roles = new HashSet<>(); // // 再根据角色查出拥有的权限 // Set permissions = new HashSet<>(); // // SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // //设置角色 // info.setRoles(roles); // //设置权限 // info.setStringPermissions(permissions);

// return info; //返回授权信息 return null; }

  1. //认证
  2. @Override
  3. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  4. System.out.println("执行了认证AuthenticationInfo");
  5. UsernamePasswordToken userToken = (UsernamePasswordToken) token;
  6. //2.根据页面提交的用户名userName查询数据库
  7. LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>(); //条件对象
  8. lqw.eq(Users::getUserId, userToken.getUsername()); //判断数据库里是否有相同的用户名
  9. Users user = usersService.getOne(lqw); //数据库查询出来的user对象
  10. //比较用户帐号userId
  11. if (user == null) { //
  12. return null; //抛出异常 UnknownAccountException
  13. }
  14. /**
  15. * 密码认证,shiro做,
  16. * 第一个参数:用户账号(userID)这个地方参数,在授权的时候,可以通过subject.getPrincipal()取出这个信息
  17. * 第二个参数:数据库的安全密码
  18. * 第三个参数:realmName
  19. */
  20. return new SimpleAuthenticationInfo(user.getId(), user.getPassword(), "userRealm");
  21. }

}

  1. <a name="FalJo"></a>
  2. ### 2.配置ShiroConfig类
  3. 这个里面可以设置哪些访问是需要权限认证的
  4. ```java
  5. package com.tj.reggie.config;
  6. import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
  7. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  8. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  9. import org.springframework.beans.factory.annotation.Qualifier;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14. @Configuration
  15. public class ShiroConfig {
  16. //加密匹配器,加密规则在这个里面指定
  17. @Bean(name = "matcher")
  18. public HashedCredentialsMatcher getHashedCredentialsMatcher() {
  19. HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
  20. //matcher就是用来指定加密规则SHA-256,也可以使用MD5
  21. matcher.setHashAlgorithmName("SHA-256");
  22. //hash加密次数
  23. matcher.setHashIterations(1);
  24. return matcher;
  25. }
  26. //创建realm对象,需要自定义类
  27. @Bean(name = "userRealm")
  28. public UserRealm userRealm(HashedCredentialsMatcher matcher) {
  29. UserRealm userRealm = new UserRealm();
  30. userRealm.setCredentialsMatcher(matcher);
  31. return userRealm;
  32. }
  33. // public IniRealm iniRealm() {
  34. // IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
  35. // return iniRealm;
  36. // }
  37. //安全对象
  38. @Bean(name = "defaultWebSecurityManager")
  39. public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
  40. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  41. //securityManager要完成校验,需要关联realm
  42. securityManager.setRealm(userRealm);
  43. return securityManager;
  44. }
  45. //Shiro过滤器
  46. @Bean(name = "shiroFilterFactoryBean")
  47. public ShiroFilterFactoryBean shiroFilter(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager securityManager) {
  48. ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
  49. //过滤器就是shiro权限校验的核心,进行认证和授权是需要securityManager的
  50. //设置安全管理器
  51. filter.setSecurityManager(securityManager);
  52. /**
  53. * 设置shiro的拦截规则
  54. * anon 匿名用户可访问(常用)
  55. * authc 认证用户可访问(常用)
  56. * user 使用RemeberMe的用户可访问
  57. * perms 拥有对某个资源的权限才可访问
  58. * role 对应的角色可访问
  59. */
  60. Map<String, String> filterMap = new HashMap<>();
  61. filterMap.put("/", "anon");//"/"表示项目根路径不拦截
  62. filterMap.put("/login.html", "anon");//表示/login.html不拦截
  63. filterMap.put("/users/login", "anon");//表示/users/login不拦截
  64. filterMap.put("/users/logout", "anon");//表示/users/logout不拦截
  65. filterMap.put("/**", "authc");//表示除了之前的,都需要认证
  66. filter.setFilterChainDefinitionMap(filterMap);
  67. // 默认的登录页面(如果不设置,会默认/login.jsp)
  68. filter.setLoginUrl("/login.html");
  69. // 授权未通过的话,会跳转到这个页面
  70. filter.setUnauthorizedUrl("/login.html");
  71. return filter;
  72. }
  73. }

3.login的API接口编写

 /**
     * 用户登录
     *
     * @param request
     * @param users
     * @return
     */
    @PostMapping("/login")
    public R<String> login(HttpServletRequest request, Users users) {
        //1.将页面提交的密码password进行md5加密处理
        String userId = users.getUserId(); //用户账号
        String password = users.getPassword();  //用户密码
        /**
         * shiro登录验证
         */
        //获取当前的subject(可理解为用户)
        Subject subject = SecurityUtils.getSubject();
        // 封装用户的登录数据token
        UsernamePasswordToken token = new UsernamePasswordToken(userId, password);
        //执行登录的方法,如果没有异常就说明登录成功
        try {
            subject.login(token);
            return R.success(token.toString());
        } catch (UnknownAccountException e) {
            return R.error("用户名不存在");
        } catch (IncorrectCredentialsException e) {
            return R.error("密码不正确");
        }
    }

4.Shiro退出登录的方法

参考:Shiro的退出登录状态的方式


    /**
     * 用户退出登录
     *
     * @param request
     * @return
     */
    @PostMapping("/logout")
    public R<String> logout(HttpServletRequest request) {
        //清理Session中保存的当前登录员工的id
        // request.getSession().removeAttribute("users");
        //shiro的方式退出登录
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            subject.logout();
        }

        return R.success("退出成功!");
    }

优化:shiro使用token认证

参考:https://blog.csdn.net/forlinkext/article/details/116749697
在resource目录下创建名为shiro.ini的文件