Apache Shiro学习笔记

Shiro

一个强大灵活的开源安全框架。干净利落的处理身份验证、授权、会话管理、加密。

  • 验证用户来核实身份
  • 对用户执行访问控制。如:判断用户是否被分配一个确定的安全角色,单端用户是否有做某件事的权限等
  • 任何环境下使用Session API,及时没有Web或EJB容器
  • 在身份验证,访问控制期间或在回话的生命周期,对时间做出反应
  • 聚集一个或多个用户安全数据的数据源,并作为一个单一的符合用户视图
  • 启用单点登录SSO功能
  • 为没有干练到登录的用户启用“remember me”服务

权限拦截Filter

Shiro有些默认的Filter实例,,并将这些Filter实例放进DefaultFilter枚举类中,可以直接使用这些枚举

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
}
枚举对应FIlter作用参数
anonorg.apache.shiro.web.filter.authc.AnonymousFilter匿名拦截器,不需要登录即可访问的资源,匿名用户或游客,一般用于过滤静态资源。无参
authcorg.apache.shiro.web.filter.authc.FormAuthenticationFilter需要认证登录才能访问无参
userorg.apache.shiro.web.filter.authc.UserFilter用户拦截器,表示必须存在用户。无参
authcBasicorg.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilterhttpBasic 身份验证拦截器。无参
rolesorg.apache.shiro.web.filter.authz.RolesAuthorizationFilter角色授权拦截器,验证用户是或否拥有角色参数可写多个,表示某些角色才能通过
多个参数时写 roles[“admin,user”],当有多个参数时,用户必须同时具备参数中的每个角色才能通过
permsorg.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter权限授权拦截器,验证用户是否拥有权限参数可写多个,表示需要某些权限才能通过
多个参数时写 perms[“user, admin”],当有多个参数时必须每个参数都通过才算可以
logoutorg.apache.shiro.web.filter.authc.LogoutFilter退出拦截器,执行后会直接跳转到shiroFilterFactoryBean.setLoginUrl()设置的 url
portorg.apache.shiro.web.filter.authz.PortFilter端口拦截器, 可通过的端口。
sslorg.apache.shiro.web.filter.authz.SslFilterssl拦截器,只有请求协议是https才能通过。
restorg.apache.shiro.web.filter.authz.HttpMethodPermissionFilter根据请求方法拦截,相当于perms[user:method],其中method为post、get、delete等

anon、authc、authcBasic、user是第一组认证过滤器
perms、port、rest、roles、ssl是第二组授权过滤器
要通过授权过滤器就要先完成登录认证操作

springboot整合shiro

依赖包

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.3.2</version>
</dependency>

Shiro配置类

@Configuration
public class ShiroConfig {
   @Bean
   public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
       ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
       // 必须设置 SecurityManager
       shiroFilterFactoryBean.setSecurityManager(securityManager);
       // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
       shiroFilterFactoryBean.setLoginUrl("/notLogin");
       // 设置无权限时跳转的 url;
       shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");

       // 设置拦截器
       Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
       //游客,开发权限
       filterChainDefinitionMap.put("/guest/**", "anon");
       //用户,需要角色权限 “user”
       filterChainDefinitionMap.put("/user/**", "roles[user]");
       //管理员,需要角色权限 “admin”
       filterChainDefinitionMap.put("/admin/**", "roles[admin]");
       //开放登陆接口
       filterChainDefinitionMap.put("/login", "anon");
       //其余接口一律拦截
       //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
       filterChainDefinitionMap.put("/**", "authc");

       shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
       System.out.println("Shiro拦截器工厂类注入成功");
       return shiroFilterFactoryBean;
   }

   /**
    * 注入 securityManager
    */
   @Bean
   public SecurityManager securityManager() {
       DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
       // 设置realm.
       securityManager.setRealm(customRealm());
       return securityManager;
   }

   /**
    * 自定义身份认证 realm;
    * <p>
    * 必须写这个类,并加上 @Bean 注解,目的是注入 CustomRealm,
    * 否则会影响 CustomRealm类 中其他类的依赖注入
    */
   @Bean
   public CustomRealm customRealm() {
       return new CustomRealm();
   }
}
自定义 realm 类,要继承AuthorizingRealm类
@Component
public class CustomRealm extends AuthorizingRealm {
    private final UserMapper userMapper;

    @Autowired
    public CustomRealm(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /**
     * 获取身份验证信息
     * Shiro中,最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
     *
     * @param authenticationToken 用户身份信息 token
     * @return 返回封装了用户信息的 AuthenticationInfo 实例
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("————身份认证方法————");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 从数据库获取对应用户名密码的用户
        String password = userMapper.getPassword(token.getUsername());
        if (null == password) {
            throw new AccountException("用户名不正确");
        } else if (!password.equals(new String((char[]) token.getCredentials()))) {
            throw new AccountException("密码不正确");
        }
        return new SimpleAuthenticationInfo(token.getPrincipal(), password, getName());
    }

    /**
     * 获取授权信息
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("————权限认证————");
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获得该用户角色
        String role = userMapper.getRole(username);
        Set<String> set = new HashSet<>();
        //需要将 role 封装到 Set 作为 info.setRoles() 的参数
        set.add(role);
        //设置该用户拥有的角色
        info.setRoles(set);
        return info;
    }
}

Subject 代表当前用户
//获得当前正在执行的subject
 Subject subject = SecurityUtils.getSubject();
subject.getUsername()  //获得用户名 String
subject.getPrincipal() //获得用户名 Object 
subject.getPassword()  //获得密码 char[]
subject.getCredentials() //获得密码 Object
登录验证
@RestController
public class LoginController {
   @Autowired    
   private ResultMap resultMap;
   @Autowired    
   private UserMapper userMapper;

   @RequestMapping(value = "/notLogin", method = RequestMethod.GET)
   public ResultMap notLogin() {
       return resultMap.success().message("您尚未登陆!");
   }

   @RequestMapping(value = "/notRole", method = RequestMethod.GET)
   public ResultMap notRole() {
       return resultMap.success().message("您没有权限!");
   }

   @RequestMapping(value = "/logout", method = RequestMethod.GET)
   public ResultMap logout() {
       Subject subject = SecurityUtils.getSubject();
       //注销
       subject.logout();
       return resultMap.success().message("成功注销!");
   }

   /**
    * 登陆
    *
    * @param username 用户名
    * @param password 密码
    */
   @RequestMapping(value = "/login", method = RequestMethod.POST)
   public ResultMap login(String username, String password) {
       // 从SecurityUtils里边创建一个 subject
       Subject subject = SecurityUtils.getSubject();
       // 在认证提交前准备 token(令牌)
       UsernamePasswordToken token = new UsernamePasswordToken(username, password);
       // 执行认证登陆
       subject.login(token);
       //根据权限,指定返回数据
       String role = userMapper.getRole(username);
       if ("user".equals(role)) {
           return resultMap.success().message("欢迎登陆");
       }
       if ("admin".equals(role)) {
           return resultMap.success().message("欢迎来到管理员页面");
       } 
       return resultMap.fail().message("权限错误!");
   }
}

对照filterChainDefinitionMap中放的filter链写接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值