技术文章第一时间送达!
作者:小LUA
cnblogs.com/LUA123/p/9337963.html
在单机版的Springboot+Shiro的基础上,这次实现共享Session。
这里没有自己写RedisManager、SessionDAO。用的 crazycake 写的开源插件
pom.xml
<project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0modelVersion > <groupId > com.examplegroupId > <artifactId > demoartifactId > <version > 0.0.1-SNAPSHOTversion > <packaging > jarpackaging > <name > demoname > <description > Demo project for Spring Bootdescription > <parent > <groupId > org.springframework.bootgroupId > <artifactId > spring-boot-starter-parentartifactId > <version > 2.0.3.RELEASEversion > <relativePath /> parent > <properties > <project.build.sourceEncoding > UTF-8project.build.sourceEncoding > <project.reporting.outputEncoding > UTF-8project.reporting.outputEncoding > <java.version > 1.8java.version > properties > <dependencies > <dependency > <groupId > org.springframework.bootgroupId > <artifactId > spring-boot-starter-data-redisartifactId > dependency > <dependency > <groupId > org.springframework.bootgroupId > <artifactId > spring-boot-starter-thymeleafartifactId > dependency > <dependency > <groupId > org.springframework.bootgroupId > <artifactId > spring-boot-starter-webartifactId > dependency > <dependency > <groupId > org.apache.shirogroupId > <artifactId > shiro-allartifactId > <version > 1.3.2version > dependency > <dependency > <groupId > com.alibabagroupId > <artifactId > fastjsonartifactId > <version > 1.2.47version > dependency > <dependency > <groupId > org.crazycakegroupId > <artifactId > shiro-redisartifactId > <version > 3.1.0version > dependency > <dependency > <groupId > org.springframework.bootgroupId > <artifactId > spring-boot-devtoolsartifactId > <scope > runtimescope > dependency > <dependency > <groupId > org.springframework.bootgroupId > <artifactId > spring-boot-starter-testartifactId > <scope > testscope > dependency > dependencies > <build > <plugins > <plugin > <groupId > org.springframework.bootgroupId > <artifactId > spring-boot-maven-pluginartifactId > plugin > <plugin > <groupId > org.apache.maven.pluginsgroupId > <artifactId > maven-compiler-pluginartifactId > <version > 3.7.0version > <configuration > <source > 1.8source > <target > 1.8target > configuration > plugin > plugins > build >project >
redis配置文件
package com.example.demo.conf;import org.springframework.beans.factory.annotation .Value;import org.springframework.context.annotation .Configuration;import org.springframework.context.annotation .PropertySource;@Configuration @PropertySource("classpath:conf/redis.properties" ) public class RedisConfig { @Value("${shiro.redis.host} " ) private String host; @Value("${shiro.redis.timeout} " ) private int timeout; public String getHost() { return host; } public void setHost(String host) { this .host = host; } public int getTimeout() { return timeout; } public void setTimeout(int timeout) { this .timeout = timeout; } }
Shiro配置文件
package com.example.demo.conf;import com.example.demo.auth.PermissionRealm;import com.example.demo.common.entity.User;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;import org.apache.shiro.spring.LifecycleBeanPostProcessor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.apache.shiro.web.servlet.SimpleCookie;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.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.util.LinkedHashMap;@Configuration public class ShiroConfig { @Bean public RedisConfig redisConfig () { return new RedisConfig(); } @Bean public RedisManager redisManager () { RedisManager redisManager = new RedisManager(); redisManager.setHost(redisConfig().getHost()); redisManager.setTimeout(redisConfig().getTimeout()); return redisManager; } @Bean public JavaUuidSessionIdGenerator sessionIdGenerator () { return new JavaUuidSessionIdGenerator(); } @Bean public RedisSessionDAO sessionDAO () { RedisSessionDAO sessionDAO = new RedisSessionDAO(); sessionDAO.setRedisManager(redisManager()); sessionDAO.setSessionIdGenerator(sessionIdGenerator()); return sessionDAO; } @Bean public SimpleCookie cookie () { SimpleCookie cookie = new SimpleCookie("SHAREJSESSIONID" ); cookie.setHttpOnly(true ); cookie.setPath("/" ); return cookie; } @Bean public DefaultWebSessionManager sessionManager () { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setGlobalSessionTimeout(redisConfig().getTimeout()); sessionManager.setDeleteInvalidSessions(true ); sessionManager.setSessionIdCookie(cookie()); sessionManager.setSessionDAO(sessionDAO()); return sessionManager; } @Bean public DefaultWebSecurityManager securityManager () { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm()); securityManager.setSessionManager(sessionManager()); return securityManager; } @Bean public RedisCacheManager redisCacheManager () { RedisCacheManager cacheManager = new RedisCacheManager(); cacheManager.setRedisManager(redisManager()); return cacheManager; } @Bean public AuthorizingRealm realm () { PermissionRealm realm = new PermissionRealm(); HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName("MD5" ); matcher.setHashIterations(10 ); matcher.setStoredCredentialsHexEncoded(true ); realm.setCredentialsMatcher(matcher); return realm; } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor () { return new LifecycleBeanPostProcessor(); } @Bean @DependsOn ("lifecycleBeanPostProcessor" ) public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator () { return new DefaultAdvisorAutoProxyCreator(); } @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean () { LinkedHashMap map = new LinkedHashMap<>(); map.put("/css/**" , "anon" ); map.put("/js/**" , "anon" ); map.put("/login" , "anon" ); map.put("/register" , "anon" ); map.put("/logout" , "logout" ); map.put("/user/**" , "authc,roles[user]" ); map.put("/admin/**" , "authc,roles[admin]" ); map.put("/**" , "authc" ); ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager()); factoryBean.setFilterChainDefinitionMap(map); factoryBean.setLoginUrl("/" ); factoryBean.setUnauthorizedUrl("/unauthorized" ); return factoryBean; } @Bean public RedisTemplate redisTemplate (RedisConnectionFactory connectionFactory) { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(connectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(User.class)); return redisTemplate; } }
UserService
package com.example.demo.service;import com.example.demo.common.entity.User;import java.util.List;public interface UserService { void addUser (User user) ; User login (User user) ; List getUsers () ; }
impl
package com.example.demo.service.impl;import com.example.demo.common.PasswordUtils;import com.example.demo.common.entity.User;import com.example.demo.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Service;import java.util.ArrayList;import java.util.List;@Service public class UserServiceImpl implements UserService { @Autowired private RedisTemplate redisTemplate; @Override public void addUser (User user) { user.setPassword(PasswordUtils.saltAndMd5(user.getUsername(),user.getPassword())); redisTemplate.boundHashOps("users" ).put(user.getUsername(), user); } @Override public User login (User user) { user.setPassword(PasswordUtils.saltAndMd5(user.getUsername(),user.getPassword())); User u = (User) redisTemplate.boundHashOps("users" ).get(user.getUsername()); if (u == null || !check(user, u)){ return null ; } return u; } @Override public List getUsers () { List list = redisTemplate.boundHashOps("users" ).values(); List users = new ArrayList<>(); list.forEach(u->{ users.add((User) u); }); return users; } private boolean check (User a, User b) { if (a.getUsername().equals(b.getUsername()) && a.getPassword().equals(b.getPassword())){ return true ; } return false ; } }
controller
package com.example.demo.controller;import com.example.demo.common.entity.User;import com.example.demo.common.response.BaseResponse;import com.example.demo.service.UserService;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.springframework.beans.factory.annotation .Autowired;import org.springframework.web.bind.annotation .RequestBody;import org.springframework.web.bind.annotation .RequestMapping;import org.springframework.web.bind.annotation .RestController;import org.springframework.web.servlet.ModelAndView;@RestController public class SimpleController { @Autowired private UserService userService; @RequestMapping("/" ) public ModelAndView index(){ return new ModelAndView("index" ); } @RequestMapping("/login" ) public BaseResponse login(@RequestBody User user){ BaseResponse response = new BaseResponse<>(0 ,"登陆成功" ); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken( user.getUsername(), user.getPassword()); subject.login(token); response.setData("/home" ); return response; } @RequestMapping("/register" ) public BaseResponse register(@RequestBody User user){ userService.addUser(user); return new BaseResponse(0 ,"注册成功" ); } @RequestMapping("/home" ) public ModelAndView home(){ ModelAndView mv = new ModelAndView("home" ); mv.addObject("users" , userService.getUsers()); return mv; } }
redis.properties
shiro.redis.host=localhost:6379 shiro.redis.timeout=1800000
applicatin.properties
#server.port=8080 server.port=8081 #server.port=8082 spring.redis.host=127.0.0.1 spring.redis.port=6379
index.html
html> <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <head > <meta charset ="UTF-8" > <title > Indextitle > <link th:href ="@{css/index.css}" rel ="stylesheet" type ="text/css" > head ><body > <div class ="container" > <div class ="header" > <h2 > 初级SpringBoot+Shiro小栗子 Node-Oneh2 > div > <div class ="main" > <div class ="left" > <div class ="form-group" > <input type ="text" name ="username" placeholder ="请输入用户名" > div > <div class ="form-group" > <input type ="password" name ="password" placeholder ="请输入密码" > div > <div class ="form-group" > <a href ="javascript:;" id ="login" > 登录a > div > <div class ="form-group" > <a href ="/home" > 点我!不登录进不去a > div > div > <div class ="right" > <div class ="form-group" > <input type ="text" name ="username" placeholder ="请输入用户名" > div > <div class ="form-group" > <input type ="password" name ="password" placeholder ="请输入密码" > div > <div class ="form-group" > <input type ="text" name ="show" placeholder ="自我介绍" > div > <div class ="form-group" > <a href ="javascript:;" id ="register" > 注册a > div > div > div > div > <script th:src ="@{js/jquery-3.3.1.min.js}" > script ><script th:src ="@{js/index.js}" > script >body >html >
home.html
html> <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <head > <meta charset ="UTF-8" > <title > Hometitle > <link th:href ="@{css/index.css}" rel ="stylesheet" type ="text/css" > head ><body > <div class ="container" > <div class ="header" > <h2 > 初级SpringBoot+Shiro小栗子 Node-Oneh2 > <a href ="/logout" > 退出登录a > div > <div class ="main" > <table class ="table" > <thead > <tr > <th > Usernameth > <th > Passwordth > <th > Showth > tr > thead > <tbody > <tr th:each ="u : ${users}" > <td > [[${u.username}]]td > <td > [[${u.password}]]td > <td > [[${u.show}]]td > tr > tbody > table > div >div >body >html >
以上两种配置各打包一次(记得留着打包好的jar包)
http://nginx.org/
解压到无中文目录,修改Nginx配置文件
upstream myapp{ server 127.0 .0 .1 :8081 weight=1 ; server 127.0 .0 .1 :8082 weight=1 ; } server{ listen 80 ; server_name myapp; location / { proxy_pass http: proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
到此,先启动两个jar包(分别是8081,Node-One;8082,Node-Two)
然后启动Nginx
浏览器访问:http://localhost/
刷新看看..
..
随便在一个节点上注册,登录,然后刷新到另外一个节点,发现不用登录就可以访问权限资源
..
GitHub
https://github.com/Mysakura/boot-shiro-session
推荐阅读(点击即可跳转阅读)
1. SpringBoot内容聚合
2. 面试题内容聚合
3. 设计模式内容聚合
4. Mybatis内容聚合
5. 多线程内容聚合
觉得不错?欢迎转发分享给更多人
我知道你 “在看 ”