springboo+shiro+redis实现登录demo

项目结构:
在这里插入图片描述
User实体类:

package com.shirodemo.bean;import java.io.Serializable;public class User implements Serializable {private int id;private String username;private String password;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';}
}

自定义sessionManager:

package com.shirodemo.common;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;public class MySessionManager extends DefaultWebSessionManager {private  static  final String AUTHORIZATION = "Authorization";//授权private  static  final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";public MySessionManager() {super();}/**** @param request* @param response* @return* @decribe 重写getSessionId作为token,然后保存在redis里面,用户下次验证*/@Overrideprotected Serializable getSessionId(ServletRequest request, ServletResponse response) {//获得请求头的tokenString id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);//选择在ajax的请求头中传递sessionId,前后端分离选择在ajax请求头中获得sessionidif(!StringUtils.isEmpty(id)){request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);return id;}else{//默认是从cookie中得到sessionidreturn super.getSessionId(request, response);}}
}

ShiroConfig:

package com.shirodemo.config;import com.shirodemo.Realm.UserRealm;
import com.shirodemo.common.MySessionManager;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.session.SessionListener;
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.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import org.apache.shiro.mgt.SecurityManager;import java.util.LinkedHashMap;
import java.util.Map;//Shiro的配置类
@Configuration
public class ShiroConfig {/*** Shiro的核心api* Subject:用户主体(把操作交给SecurityManager)* SecurityManager:安全管理器(关联Realm)* Realm:Shiro连接数据的桥梁*//*** 创建ShiroFilterFactoryBean* @param* @return*/@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager  securityManager) {ShiroFilterFactoryBean  shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//        Map filters = shiroFilterFactoryBean.getFilters();
//        filters.put("perms", new RestAuthorizationFilter());//设置安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);//配置未认证跳转页面//使用shiro内置过滤器拦截/*** 常用的过滤器*      anon:无须认证(登录)可以访问*      authc:必须认证才可以访问*      user: 如果使用remenberMe的功能才可以直接访问*      perms:该资源必须得到资源权限才可以访问*      role:该资源得到角色权限才可以访问*/shiroFilterFactoryBean.setLoginUrl("/backLogin");//配置未授权跳转页面shiroFilterFactoryBean.setUnauthorizedUrl("/unAthc");Map<String,String> filterMap = new LinkedHashMap<String,String>();filterMap.put("/login","anon");//拦截根目录filterMap.put("/swagger-ui.html","anon");filterMap.put("/static/**", "anon");filterMap.put("/swagger/**","anon");filterMap.put("/webjars/**", "anon");filterMap.put("/swagger-resources/**","anon");filterMap.put("/v2/**","anon");filterMap.put("/img","anon");//文件资源放行filterMap.put("/doLogin","anon");//拦截根目录//资源授权例子//添加需要授权的资源filterMap.put("/role","perms[role:list]");filterMap.put("/user","perms[user:list]");filterMap.put("/user/addUser","perms[user:add]");//用户添加权限filterMap.put("/user/updateUser","perms[user:update]");//用户更新权限filterMap.put("/*","authc");//拦截根目录//未登录,shiro应重定向到登录界面,此处返回未登录状态信息由前端控制跳转页面shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);return shiroFilterFactoryBean;}@Beanpublic DefaultWebSessionManager sessionManager(){//DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();MySessionManager mySessionManager = new MySessionManager(); //使用自定义的session管理器mySessionManager.setCacheManager(cacheManager()); //设置缓存管理器mySessionManager.setSessionDAO(redisSessionDAO());//设置sessionDAOmySessionManager.setSessionIdUrlRewritingEnabled(true);return  mySessionManager;}/*** 创建Realm,需要自定义* @return*/@Bean(name = "userRealm")public UserRealm getRealm(){UserRealm  userRealm = new  UserRealm();//userRealm.setCredentialsMatcher(credentialsMatcher());userRealm.setCachingEnabled(true); //开启缓存return userRealm;}/*** 盐值加密* @return*/
//    @Bean(name="credentialsMatcher")
//    public HashedCredentialsMatcher credentialsMatcher()
//    {
//        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//
//        hashedCredentialsMatcher.setHashAlgorithmName("MD5");  //加密算法名
//
//        hashedCredentialsMatcher.setHashIterations(2); //加密次数
//
//        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true); //采用hash散列算法加密
//
//        return hashedCredentialsMatcher;
//    }/*** 安全管理器* @param userRealm* @return*/@Bean(name = "securityManager")public SecurityManager  getDefaultSecurityManager(@Qualifier("userRealm") UserRealm userRealm){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();//配置自定义session管理,使用redissecurityManager.setSessionManager(sessionManager());//配置缓存,使用redissecurityManager.setCacheManager(cacheManager());securityManager.setRealm(getRealm());return  securityManager;}/*** 生命周期处理器* @return*/@Bean(name="lifecycleBeanPostProcessor")public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){return new LifecycleBeanPostProcessor();}/**** redisManager管理器* @return*/@Beanpublic RedisManager redisManager(){RedisManager redisManager = new RedisManager();//redis配置redisManager.setHost("127.0.0.1");redisManager.setPort(6379);redisManager.setPassword("123456");return redisManager;}/*** shiro缓存管理器,** @return*/public RedisCacheManager cacheManager(){RedisCacheManager redisCacheManager = new RedisCacheManager();redisCacheManager.setRedisManager(redisManager());redisCacheManager.setPrincipalIdFieldName("username");//根据用户名缓存redisCacheManager.setExpire(200000);//设置缓存时间return  redisCacheManager;}/** session dao* @return*/@Beanpublic RedisSessionDAO redisSessionDAO(){RedisSessionDAO redisSessionDAO = new RedisSessionDAO();redisSessionDAO.setRedisManager(redisManager());return  redisSessionDAO;}}登录接口:package com.shirodemo.controller;import com.alibaba.fastjson.JSONObject;
import com.shirodemo.bean.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class LoginController {@PostMapping("/doLogin")public  String doLogin(@RequestBody User user){JSONObject jsonObject = new JSONObject();Subject subject = SecurityUtils.getSubject();//根据用户名和密码生成tokenUsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(),user.getPassword());try{subject.login(usernamePasswordToken);jsonObject.put("code",200);jsonObject.put("msg","登录成功");jsonObject.put("token",subject.getSession().getId());//把token发送给前端}catch (IncorrectCredentialsException e){jsonObject.put("msg","密码错误");}catch (LockedAccountException e){jsonObject.put("msg","用户账号已被冻结");}catch (UnknownAccountException e){jsonObject.put("msg","该用户不存在");}return jsonObject.toJSONString();}@GetMapping(value= "/unAthc")public String unAthc(){System.out.println("跳转到未授权页面");JSONObject jsonObject = new JSONObject();jsonObject.put("mycode","403");jsonObject.put("msg","未授权");return jsonObject.toJSONString();}}

UserMapper:

package com.shirodemo.dao;import com.shirodemo.bean.User;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper {User getUserByUsername(String username);
}

UserService:

package com.shirodemo.service;import com.shirodemo.bean.User;public interface UserService {User getUserByUsername(String username);
}

UserServiceImpl

package com.shirodemo.service.impl;import com.shirodemo.bean.User;
import com.shirodemo.dao.UserMapper;
import com.shirodemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl implements UserService {@AutowiredUserMapper userMapper;@Overridepublic User getUserByUsername(String username) {return userMapper.getUserByUsername(username);}
}

自定义UserRealm

package com.shirodemo.Realm;import com.shirodemo.bean.User;
import com.shirodemo.service.UserService;
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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;import java.util.HashSet;
import java.util.List;
import java.util.Set;public class UserRealm  extends AuthorizingRealm {@AutowiredUserService tbUserService;/**** @param principalCollection* @return* @describe执行授权逻辑*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行授权逻辑");//给当前登录用户授权SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        Subject subject = SecurityUtils.getSubject();
//        //得到User
//        User tbUser =  (User)subject.getPrincipal();
//        //我这里是从数据库中得到权限字符
//        //例如我数据库中保存的是user:list这样的字符
//        System.out.println(tbUser);
//        List authority = tbUserService.getAuthorityByName(tbUser.getUsername());
//        System.out.println(authority);
//        /**
//         * 1:先查出用户名
//         * 2:根据用户名查询出用户id
//         * 3:根据用户id查询出role_id
//         * 4:根据role_id查询出perms_id
//         * 5:根据perms_id查询具体权限
//         * 6:然后封装在一个set中进行授权处理
//         */
//        Set set  = new HashSet();
//        for(String perms : authority)
//        {
//            if(null != perms)
//                set.add(perms);
//        }
//
//        info.setStringPermissions(set);return info;}/**** @param authenticationToken* @return* @throws AuthenticationException* @decribe 执行认证(登录)逻辑*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("执行认证(登录)逻辑");UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;//System.out.println(token.getUsername());//需要加密和解密User tbUser= (User)tbUserService.getUserByUsername(token.getUsername());//System.out.println(tbUser);String password = tbUser.getPassword();//这里直接拿Username生成盐值,也可以自定义//ByteSource credentialsSalt = ByteSource.Util.bytes(tbUser.getUsername());if(("").equals(password)){// throw new AuthenticationException();return null; //shiro底层会返回一个UnknownAccountException}return new SimpleAuthenticationInfo(tbUser,tbUser.getPassword(),getName());}
}

yml:

server:port: 8099spring:profiles:active: devdruid:login:username: rootpassword: root---
spring:profiles: devdatasource:driverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/shirodemo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTCusername: rootpassword : roottype: com.alibaba.druid.pool.DruidDataSource#连接池配置# 初始化大小,最小等待连接数量,最大等待连接数量,最大连接数initialsize: 1minidle: 1maxidle: 5maxActive: 20#最长等待时间maxWait: 6000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: truetestOnReturn: false# 打开PSCache,并且指定每个连接上PSCache的大小poolPreparedStatements: falsemaxPoolPreparedStatementPerConnectionSize: 20# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙filters: stat,wall,log4j# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000# 合并多个DruidDataSource的监控数据#spring.datasource.useGlobalDataSourceStat=true---mybatis-plus:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.shirodemo.bean
pagehelper:helperDialect: mysqlreasonable: truesupportMethodsArguments: truepageSizeZero: false #pageSize=0---spring:redis:port: 6379database: 0host: 127.0.0.1password: 123456#默认为没有密码jedis:pool:#连接池最大连接数max-active: 8#连接池最大阻塞时间(-1为没有限制)max-wait: -1#连接池最大空闲连接max-idle: 5#连接池最少空闲连接min-idle: 0timeout: 10000

结果:
在这里插入图片描述

redis缓存:
在这里插入图片描述


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部