spring boot 使用 shiro

1.引用依赖包:(官方文档:shiro-redis/docs at master · alexxiyang/shiro-redis · GitHub

         <!-- shiro 依赖包,因为我需要把Session存储在redis,所以使用了这个依赖包  -->
        <dependency>
            <groupId>org.crazycake</groupId>
            <artifactId>shiro-redis-spring-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>

2.配置application.yml文件

shiro-redis:
  enabled: true
  redis-manager:
    host: 127.0.0.1:6379

3.编写shiro 相关配置,有5个文件,分别是MySessionManager(自定义shiro Session管理器)、MyRealm(自定义存储用户信息)、MyCredentialsMatcher(自定义密码验证器)、MyAuthenticationFilter(自定义拦截过滤器)、ShiroConfig(shiro配置类)。以下分别贴出各个文件的代码 

MySessionManager:自定义shiro Session管理器

import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;

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

/*自定义shiro Session管理器*/
public class MySessionManager extends DefaultWebSessionManager {

    private static  final  String Token_Header="test_id";

    /*shiro 中的SessionId 通过header的test_id 获取 */
    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response){
        HttpServletRequest httpServletRequest= WebUtils.toHttp(request);
        String sessionId=  httpServletRequest.getHeader(Token_Header);
        return sessionId;
    }
}

MyRealm:自定义存储用户信息

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.springframework.beans.factory.annotation.Autowired;

import java.util.List;

//通过重写AuthorizingRealm,自定义存储用户的信息
public class MyRealm extends AuthorizingRealm {

    @Autowired
    Service service;

    /*用户认证的方法*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        //查询数据库中的用户名信息
        User user = service.getUserByUserName(username);
        if (user == null) {
            throw new UnknownAccountException("账号/密码错误");
        }
        String pwd =user.getF_password();
        return new SimpleAuthenticationInfo(username, pwd, getName());
    }

    /*用户授权的方法*/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        //查询数据库中的用户名信息
        UserDto user = service.getUserByUserName(username);

        // 查询数据库获取用户角色信息,并添加到授权信息中
        List<String> roles = user.getLstAccessRoles();
        authorizationInfo.addRoles(roles);

        // 查询数据库获取用户权限信息,并添加到授权信息中
        List<String> permissions =user.getLstAccessApis();
        authorizationInfo.addStringPermissions(permissions);

        return authorizationInfo;
    }
}

MyCredentialsMatcher:自定义密码验证器

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;

/*密码验证器,需要解密后匹配*/
public class MyCredentialsMatcher extends SimpleCredentialsMatcher {

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info){
        UsernamePasswordToken passwordToken=(UsernamePasswordToken) token;
        String pwd=new String(passwordToken.getPassword());
        String dbPwd=(String) info.getCredentials();
        return pwd.equals(dbPwd);
    }


}

MyAuthenticationFilter:自定义拦截过滤器

import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class MyAuthenticationFilter extends FormAuthenticationFilter {

    /*重新请求被拦截后的响应体,返回统一格式*/
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response){
        HttpServletResponse httpServletResponse=(HttpServletResponse)response;
        ServiceResult result=new ServiceResult();
        result.isFailure("无操作权限");
        try{
        httpServletResponse.setContentType("application/json; charset=utf-8");

        PrintWriter writer = httpServletResponse.getWriter();
        String json = JSON.toJSONString(result, SerializerFeature.WriteMapNullValue);
        writer.append(json);
        writer.flush();
        writer.close();
        }
        catch (IOException ex){
            throw new RuntimeException(ex);
        }

        return false;
    }
}

ShiroConfig:shiro配置类

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.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/*
* 配置 shiro的过滤器
* 过滤器中配置 安全管理器
*
* */
@Configuration
public class ShiroConfig {

    @Autowired
    RedisSessionDAO redisSessionDAO;

    @Autowired
    RedisCacheManager redisCacheManager;

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();

        filterFactoryBean.setSecurityManager(securityManager());
        Map<String,String> map=new LinkedHashMap<>();

        //所有请求/login的不拦截
        map.put("/login/**","anon");//允许  需要设置login为anon
        //拦截所有,要有顺序,先设置允许访问的,再设置拦截的
        map.put("/**","authc");

        filterFactoryBean.setFilterChainDefinitionMap(map);

        Map<String, Filter> filterMap=new LinkedHashMap<>();
        //不能把Filter交给spring管理,如果是spring管理,最后都会走到这个Filter,会导致anon失效
        filterMap.put("authc",new MyAuthenticationFilter());
        filterFactoryBean.setFilters(filterMap);
        return filterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        MyRealm myRealm=myRealm();
        //把密码验证器放到Realm中
        myRealm.setCredentialsMatcher(credentialsMatcher());
        //添加域到安全管理器中
        manager.setRealm(myRealm);
        //添加会话管理器到安全管理器中
        manager.setSessionManager(webSessionManager());
        //添加缓存管理器到安全管理器中
        manager.setCacheManager(redisCacheManager);
        return manager;
    }

    /*Session管理器*/
    @Bean
    public DefaultWebSessionManager webSessionManager() {

        MySessionManager manager=new MySessionManager();
        //设置Session会话DAO
        manager.setSessionDAO(redisSessionDAO);
        //禁用cookies
        manager.setSessionIdCookieEnabled(false);
        //过期时间为1分钟
        manager.setGlobalSessionTimeout(1*60000);
        //启用会话验证调度器,会话验证调度器是一个后台线程,用于定期检查和验证会话是否过期
        manager.setSessionValidationSchedulerEnabled(true);

        return manager;
    }

    @Bean
    GDSSRealm myRealm(){return new MyRealm();};

    @Bean
    MyCredentialsMatcher credentialsMatcher(){return new MyCredentialsMatcher();}

使用:


    @Autowired
    RedisCacheManager redisCacheManager;

    @GetMapping("/login")
    public String login(){
        //传入参数false,是为了让shiro不自动创建sessionid,而是直接从header拿 
        //Session session=SecurityUtils.getSubject().getSession(false);
        
        //获取Session,会自动创建Sessionid,如果不想自动创建则传入false参数
        Session session=SecurityUtils.getSubject().getSession();
        //重新设置过期时间
        session.setTimeout(loginTimeout*60000);
        //存储
        session.setAttribute("name","test name");
        //获取
        String res = session.getAttribute("name");

        //存储cache
        redisCacheManager.getCache("ip").put("name","lyy"+ LocalDateTime.now());

        return res;
       
    }

redis存储结果:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值