Spring Boot整合Shiro

  • A+
所属分类:Java片段

Shiro简介

Apache Shiro是Java的一个安全框架

Shiro是一个强大的简单易用的Java安全框架,主要用来更便捷的认证、授权、加密、会话管理、与Web集成、缓存等

Shiro使用起来小而简单

spring中有spring security ,是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。

shiro不依赖于spring,shiro不仅可以实现web应用的权限管理,还可以实现c/s系统,分布式系统权限管理,

shiro属于轻量框架,越来越多企业项目开始使用shiro

核心概念

Shiro架构

Spring Boot整合Shiro

  1. subject:主体 主体可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
  2. authenticator: 认证器 主体进行认证最终通过authenticator进行的。
  3. authorizer: 授权器 主体进行授权最终通过authenticator进行的。
  4. sessionManager:会话管理 web应用中一般是用web容器对session进行管理,shiro也提供一套session管理的方式。
  5. sessionDao: 通过sessionDao管理session数据,
  6. cacheManager: 缓存管理器 主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和 ehcache整合对缓存数据进行管理。
  7. realm: 领域 相当于数据源,通过realm存取认证、授权相关数据。
  8. cryptography: 密码管理 提供了一套加密/解密的组件,方便开发。比如 提供常用的散列、加/解密等功能。

Subject账户主体

  1. 可以是人、爬虫、当前跟软件交互的东西
  2. 在shiro当中我们可以统称"用户" 在代码的任何地方,你都能轻易的获得Shiro Subject。
  3. 一旦获得Subject,你就可以立即获得你希望用Shiro为当前用户做的90%的事情 ,登录、退、访问会话、执行授权检查等

SecurityManager安全管理器

  1. SecurityManager则管理所有用户的安全操作
  2. 引用了多个内部嵌套安全组件,是Shiro框架的核心
  3. 你可以把它看成DispatcherServlet前端控制器。
  4. 用于调度各种Shiro框架的服务

Realm领域对象

  1. Realms则是用户的信息认证器和用户的权限认证器
  2. 执行认证(登录)和授权(访问控制)时,Shiro会从应用配置的Realm中查找很多内容
  3. Realm 可以理解为读取用户信息、角色及权限的 DAO
  4. SecurityManager要验证用户身份与权限,那么它需要从Realm获取相应的信息进行比较以确定用户身份是否合法;
  5. 可以把Realm看成DataSource,即安全数据源。

依赖配置

添加maven依赖

<!--整合shiro-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.3</version>
</dependency>

创建Shiro配置类

创建Realm领域对象

/**
 * @Created by 墨云
 * @Description TODO
 * @Date 2020/9/16 22:31
 */
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private SysUserService sysUserService;


    /**
     * 认证方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String account = token.getUsername();
        String password = String.valueOf(token.getPassword());
        //根据账号从数据库查询用户信息
        SysUser user = sysUserService.getByAccount(account);
        if(user != null ){
            //如果密码正确,MD5则加密对比
            if(user.getPassword().equals(password)){
                SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
                return info;
            }else{
                return null;
            }
        }else{
            return null;
        }
    }


    /**
     * 授权方法
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取用户名
        String username = (String) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 给该用户设置角色
        authorizationInfo.setRoles(sysUserService.getRoles(username));
        // 给该用户设置权限
        authorizationInfo.setStringPermissions(sysUserService.getPermissions(username));
        return authorizationInfo;
    }

}

创建AuthcFilter过滤器

/**
 * @Description TODO
 * @Date 2020/9/21 9:09
 * @Created by 墨云
 */
public class AuthcFilter extends FormAuthenticationFilter {

    /**
     * 解决session失效时的重定向问题
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request, response);

        //如果用户已登陆
        if (subject.getPrincipal() != null) {
            return true;
        }else {
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            Map<String,Object> map = new HashMap<>();
            map.put("code", 403);
            map.put("msg", "登录超时!");
            map.put("state", false);
            setResponse(httpServletResponse,map);
            return false;
        }
    }


    /**
     * 设置响应信息
     * @param response
     * @param map
     */
    private void setResponse(HttpServletResponse response, Map<String,Object> map){
        try {
            response.reset();
            response.setContentType("application/json");
            response.setHeader("Cache-Control", "no-store");
            response.setCharacterEncoding("UTF-8");
            PrintWriter pw = response.getWriter();
            String failMsg = JSONObject.toJSONString(map);
            pw.write(failMsg);
            pw.flush();
        }catch (IOException e){
        }

    }
}

创建登陆控制器类

/**
 * @Created by 墨云
 * @Description TODO
 * @Date 2020/9/16 22:00
 */
@RestController
@RequestMapping("/login")
public class LoginController {

    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

    @PostMapping("/doLogin")
    public BaseResponse doLogin(@RequestBody SysUser user){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getAccount(), user.getPassword());
        try {
            //进行验证,这里可以捕获异常,然后返回对应信息
            subject.login(token);
        } catch (UnknownAccountException e) {
            logger.error("登录失败 ----> account:【{}】,password:【{}】",user.getAccount(),user.getPassword());
            e.printStackTrace();
            return BaseResponse.renderFail("用户名或密码错误");
        }
        SysUser sysUser = (SysUser)SecurityUtils.getSubject().getPrincipal();
        return BaseResponse.renderSuccess("登陆成功",sysUser);
    }


    @PostMapping("/logout")
    public BaseResponse logOut(){
        Subject lvSubject=SecurityUtils.getSubject();
        lvSubject.logout();
        return BaseResponse.renderSuccess("退出成功");
    }

}

用postman进行测试,访问http://localhost:9000/base/sysUser/getUserById?id=1接口,此时会提示提示登陆超时Spring Boot整合Shiro

当我们调用登陆接口登陆成功之后http://localhost:9000/base/login/doLogin,便能成功访问到数据

Spring Boot整合Shiro

以上便是SpringBoot整合Shiro的简单过程

其他过滤器

如果在Shiro中需要自定义自定义过滤器,则如9.3中的AuthcFilter创建过程类似,创建一个类,继承对应的Filter,重写对应的方法,再将其注册到shiroFilterFactoryBean中,同9.3中的ShrioConfig类似,Shiro中默认的过滤器主要有以下几种:

public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    authcBearer(BearerHttpAuthenticationFilter.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简介

anon 开放权限,匿名用户可以直接访问的
authc 需要身份认证才能访问
logout 注销,执行后会直接跳转到 shiroFilterFactoryBean.setLoginUrl(); 设置的 url,即登录页面
roles[admin] 参数可写多个,表示是某个或某些角色才能通过;多个参数时写roles["admin,user"],当有多个参数时必须每个参数都通过才算通过
perms[user] 参数可写多个,表示需要某个或某些权限才能通过;多个参数时写perms[“user, admin”],当有多个参数时必须每个参数都通过才算通过
  • 云说Java
  • 关注公众号获取更多资源
  • weinxin
  • Java栈记
  • 关注公众号获取更多资源
  • weinxin
墨云

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: