Shiro的基本使用

1、依赖

 

<!-- shiro核心包 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.5.3</version>
</dependency>
<!-- shiro与redis整合 -->
<dependency>
    <groupId>org.crazycake</groupId>
    <artifactId>shiro-redis</artifactId>
    <version>3.2.3</version>
</dependency>
<!-- shiro与spring整合 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.3</version>
</dependency>

2、配置

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shiro?characterEncoding=utf-8
    username: root
    password: 123456
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
  redis:
    host: xxx.xxx.xxx.xxx
    port: 6379

3、流程

1、配置Controller

用户输入用户名和密码后发送login请求给后端,后端接收到用户名和密码后使用SecurityUtils获取Subject,初始化一个UserPasswordToken将用户名和密码放入,调用subject.login方法。

2、自定义Realm

自定义Realm集成AuthorizingRealm,重写doGetAuthorizationInfo和doGetAuthenticationInfo以及setName方法,在setName方法里设置自定义Realm的名字。在doGetAuthenticationInfo进行认证处理,在doGetAuthorizationInfo进行授权处理。

package com.wx.springboot.realm;
import com.wx.springboot.entity.Permission;
import com.wx.springboot.entity.Role;
import com.wx.springboot.entity.User;
import com.wx.springboot.repository.UserRepository;
import com.wx.springboot.utils.Constants;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.Set;

/**
 * Description:
 * Author:逗你妹
 * Date:2020/5/16
 */
public class CustomeRealm extends AuthorizingRealm {

    @Autowired
    UserRepository userRepository;

    @Override
    public void setName(String name) {
        super.setName("customeRealm");
    }

    /**
      * @Description:授权
      * @Date: 2020/5/16
      **/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        User user = (User)principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<Role> roles = user.getRoles();
        for (Role role : roles){
            info.addRole(role.getName());
            for (Permission perm : role.getPermissions()){
                info.addStringPermission(perm.getName());
            }
        }
        return info;
    }

    /**
      * @Description:认证
      * @Date: 2020/5/16
      **/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        UsernamePasswordToken upToken = (UsernamePasswordToken)authenticationToken;
        String username = upToken.getUsername();
        User user = userRepository.findUserByUsername(username);
        if(!StringUtils.isEmpty(user)){
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
            // 加盐
            info.setCredentialsSalt(ByteSource.Util.bytes(username));
            return info;
        }else{
            return null;
        }
    }
}

3、配置Shiro配置文件

package com.wx.springboot.config;

import com.wx.springboot.realm.CustomeRealm;
import com.wx.springboot.utils.Constants;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

/**
 * Description:
 * Author:逗你妹
 * Date:2020/5/17
 */
@Configuration
public class ShiroConfiguration {

    private String host = "xxx.xxx.xxx.xxx:6379";
    private String password = "xxxxxx";
    // 配置自定义的Realm
    @Bean
    public CustomeRealm getRealm(){
        CustomeRealm customeRealm = new CustomeRealm();
        // 配置凭证匹配器
        customeRealm.setCredentialsMatcher(getHashCredential());
        return customeRealm;
    }

    // 配置安全管理器
    @Bean
    public SecurityManager getSecurityManager(CustomeRealm realm){
        DefaultSecurityManager securityManager = new DefaultWebSecurityManager(realm);
        // 设置自定义session管理
        securityManager.setSessionManager(sessionManager());
        // 设置自定义缓存
        securityManager.setCacheManager(cacheManager());
        // 设置自定义Realm
        securityManager.setRealm(realm);
        return securityManager;
    }
    // 设置凭证匹配器
    @Bean
    public HashedCredentialsMatcher getHashCredential(){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName(Constants.ALGORITHNAME);
        matcher.setHashIterations(Constants.HASHINTERATIONS);
        matcher.setStoredCredentialsHexEncoded(true);
        return matcher;
    }

    // Filter工厂,设置对应的过滤条件和跳转请求
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        // 创建Shiro过滤器工厂
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        factoryBean.setSecurityManager(securityManager);
        // 通用配置(设置登录页面,成功页面,失败页面)
        factoryBean.setLoginUrl("/login/authLogin?code=1");
        factoryBean.setUnauthorizedUrl("/login/authLogin?code=2");
        // 设置过滤器集合
        /**
         * key:访问链接
         *      支持通配符
         * value:过滤器类型
         * shiro常用类型
         *      anon:匿名访问(所有人都可以访问)
         *      authc:认证后访问(需要先登录成功后才可以访问)
         */
        LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();
        // filterMap.put("/home/page", "perms[home:page]");
        // filterMap.put("/home/page", "roles[role1]");
        filterMap.put("/login/login", "anon");
        filterMap.put("/home/page", "authc");
        filterMap.put("/user/**", "authc");
        factoryBean.setFilterChainDefinitionMap(filterMap);
        return factoryBean;
    }

    // 1.配置Shiro RedisManager 管理器
    public RedisManager redisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPassword(password);
        return redisManager;
    }

    // 2.配置Shiro缓存机制 使用Redis实现
    public RedisCacheManager cacheManager(){
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }
    // 3.配置SessionDao
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }
    // 4.配置会话管理器,指定sessionDao的依赖关系
    public DefaultWebSessionManager sessionManager(){
        CustomSessionManager customSessionManager = new CustomSessionManager();
        customSessionManager.setSessionDAO(redisSessionDAO());
        return customSessionManager;
    }
    // 配置Shiro注解支持
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
}

4、自定义Session管理器

package com.wx.springboot.config;

import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;

/**
 * Description:自定义session管理器
 * Author:逗你妹
 * Date:2020/5/17
 */
public class CustomSessionManager extends DefaultWebSessionManager {

    private static final String AUTHORIZATION = "Authorization";
    private static final String SESSION_ID_SOURCE = "header";

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
        if(!StringUtils.isEmpty(id)){
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return id;
        }else{
            return super.getSessionId(request, response);
        }
    }
}

5、配置全局异常类处理

package com.wx.springboot.config;
import com.wx.springboot.constant.Result;
import com.wx.springboot.constant.ResultCode;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.naming.AuthenticationException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Description:
 * Author:逗你妹
 * Date:2020/5/16
 */
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {AuthenticationException.class, AuthorizationException.class})
    public Result exceptionHandler(HttpServletRequest request, HttpServletResponse response,Exception e){
        if(e instanceof  AuthorizationException){
            // 未登录
            return new Result(ResultCode.UNAUTHORISE);
        }else if(e instanceof AuthenticationException){
            // 未授权
            return new Result(ResultCode.UNAUTHENTICATED);
        }else{
            return new Result(ResultCode.SERVERERROR);
        }
    }
}

4、Shiro常用注解和权限

在Controller方法上或者类上可以根据角色和权限进行注解设置。

角色:@RequiresRoles(value = {"xxx"}):需要xxx角色才可以访问类或方法

权限:@RequiresPermissions(value = {"xxx"}):需要xxx权限才可以访问类或方法

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值