SpringBoot+Shiro+Redis共享Session入門(mén)
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
? 作者?|??蘇先生139
來(lái)源 |? urlify.cn/V7Jbeu
66套java從入門(mén)到精通實(shí)戰(zhàn)課程分享
在單機(jī)版的Springboot+Shiro的基礎(chǔ)上,這次實(shí)現(xiàn)共享Session。這里沒(méi)有自己寫(xiě)RedisManager、SessionDAO。用的 crazycake 寫(xiě)的開(kāi)源插件
pom.xml
"1.0"?encoding="UTF-8"?>
"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">
????4.0.0
????com.example
????demo
????0.0.1-SNAPSHOT
????jar
????demo
????Demo?project?for?Spring?Boot
????
????????org.springframework.boot
????????spring-boot-starter-parent
????????2.0.3.RELEASE
???????? ?
????
????
????????UTF-8
????????UTF-8
????????1.8
????
????
????????
????????????org.springframework.boot
????????????spring-boot-starter-data-redis
????????
????????
????????????org.springframework.boot
????????????spring-boot-starter-thymeleaf
????????
????????
????????????org.springframework.boot
????????????spring-boot-starter-web
????????
????????
????????
????????????org.apache.shiro
????????????shiro-all
????????????1.3.2
????????
????????
????????
????????????com.alibaba
????????????fastjson
????????????1.2.47
????????
????????
????????
????????????org.crazycake
????????????shiro-redis
????????????3.1.0
????????
????????
????????????org.springframework.boot
????????????spring-boot-devtools
????????????runtime
????????
????????
????????????org.springframework.boot
????????????spring-boot-starter-test
????????????test
????????
????
????
????????
????????????
????????????????org.springframework.boot
????????????????spring-boot-maven-plugin
????????????
????????????
????????????????org.apache.maven.plugins
????????????????maven-compiler-plugin
????????????????3.7.0
????????????????
????????????????????<source>1.8source>
????????????????????1.8
????????????????
????????????
????????
????
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();?????//?crazycake?實(shí)現(xiàn)
????????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();?//?crazycake?實(shí)現(xiàn)
????????sessionDAO.setRedisManager(redisManager());
????????sessionDAO.setSessionIdGenerator(sessionIdGenerator());?//??Session?ID?生成器
????????return?sessionDAO;
????}
????@Bean
????public?SimpleCookie?cookie(){
????????SimpleCookie?cookie?=?new?SimpleCookie("SHAREJSESSIONID");?//??cookie的name,對(duì)應(yīng)的默認(rèn)是?JSESSIONID
????????cookie.setHttpOnly(true);
????????cookie.setPath("/");????????//??path為?/?用于多個(gè)系統(tǒng)共享JSESSIONID
????????return?cookie;
????}
????@Bean
????public?DefaultWebSessionManager?sessionManager(){
????????DefaultWebSessionManager?sessionManager?=?new?DefaultWebSessionManager();
????????sessionManager.setGlobalSessionTimeout(redisConfig().getTimeout());????//?設(shè)置session超時(shí)
????????sessionManager.setDeleteInvalidSessions(true);??????//?刪除無(wú)效session
????????sessionManager.setSessionIdCookie(cookie());????????????//?設(shè)置JSESSIONID
????????sessionManager.setSessionDAO(sessionDAO());?????????//?設(shè)置sessionDAO
????????return?sessionManager;
????}
????/**
?????*?1.?配置SecurityManager
?????*?@return
?????*/
????@Bean
????public?DefaultWebSecurityManager?securityManager(){
????????DefaultWebSecurityManager?securityManager?=?new?DefaultWebSecurityManager();
????????securityManager.setRealm(realm());??//?設(shè)置realm
????????securityManager.setSessionManager(sessionManager());????//?設(shè)置sessionManager
//????????securityManager.setCacheManager(redisCacheManager());?//?配置緩存的話,退出登錄的時(shí)候crazycake會(huì)報(bào)錯(cuò),要求放在session里面的實(shí)體類(lèi)必須有個(gè)id標(biāo)識(shí)
????????return?securityManager;
????}
????/**
?????*?2.?配置緩存
?????*?@return
?????*/
//????@Bean
//????public?CacheManager?cacheManager(){
//????????EhCacheManager?ehCacheManager?=?new?EhCacheManager();
//????????ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
//????????return?ehCacheManager;
//????}
????@Bean
????public?RedisCacheManager?redisCacheManager(){
????????RedisCacheManager?cacheManager?=?new?RedisCacheManager();???//?crazycake?實(shí)現(xiàn)
????????cacheManager.setRedisManager(redisManager());
????????return?cacheManager;
????}
????/**
?????*?3.?配置Realm
?????*?@return
?????*/
????@Bean
????public?AuthorizingRealm?realm(){
????????PermissionRealm?realm?=?new?PermissionRealm();
????????HashedCredentialsMatcher?matcher?=?new?HashedCredentialsMatcher();
????????//?指定加密算法
????????matcher.setHashAlgorithmName("MD5");
????????//?指定加密次數(shù)
????????matcher.setHashIterations(10);
????????//?指定這個(gè)就不會(huì)報(bào)錯(cuò)
????????matcher.setStoredCredentialsHexEncoded(true);
????????realm.setCredentialsMatcher(matcher);
????????return?realm;
????}
????/**
?????*?4.?配置LifecycleBeanPostProcessor,可以來(lái)自動(dòng)的調(diào)用配置在Spring?IOC容器中?Shiro?Bean?的生命周期方法
?????*?@return
?????*/
????@Bean
????public?LifecycleBeanPostProcessor?lifecycleBeanPostProcessor(){
????????return?new?LifecycleBeanPostProcessor();
????}
????/**
?????*?5.?啟用IOC容器中使用Shiro的注解,但是必須配置第四步才可以使用
?????*?@return
?????*/
????@Bean
????@DependsOn("lifecycleBeanPostProcessor")
????public?DefaultAdvisorAutoProxyCreator?defaultAdvisorAutoProxyCreator(){
????????return?new?DefaultAdvisorAutoProxyCreator();
????}
????/**
?????*?6.?配置ShiroFilter
?????*?@return
?????*/
????@Bean
????public?ShiroFilterFactoryBean?shiroFilterFactoryBean(){
????????LinkedHashMap?map?=?new?LinkedHashMap<>();
????????//?靜態(tài)資源
????????map.put("/css/**",?"anon");
????????map.put("/js/**",?"anon");
????????//?公共路徑
????????map.put("/login",?"anon");
????????map.put("/register",?"anon");
????????//map.put("/*",?"anon");
????????//?登出,項(xiàng)目中沒(méi)有/logout路徑,因?yàn)閟hiro是過(guò)濾器,而SpringMVC是Servlet,Shiro會(huì)先執(zhí)行
????????map.put("/logout",?"logout");
????????//?授權(quán)
????????map.put("/user/**",?"authc,roles[user]");
????????map.put("/admin/**",?"authc,roles[admin]");
????????//?everything?else?requires?authentication:
????????map.put("/**",?"authc");
????????ShiroFilterFactoryBean?factoryBean?=?new?ShiroFilterFactoryBean();
????????//?配置SecurityManager
????????factoryBean.setSecurityManager(securityManager());
????????//?配置權(quán)限路徑
????????factoryBean.setFilterChainDefinitionMap(map);
????????//?配置登錄url
????????factoryBean.setLoginUrl("/");
????????//?配置無(wú)權(quán)限路徑
????????factoryBean.setUnauthorizedUrl("/unauthorized");
????????return?factoryBean;
????}
????/**
?????*?配置RedisTemplate,充當(dāng)數(shù)據(jù)庫(kù)服務(wù)
?????*?@return
?????*/
????@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 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,"注冊(cè)成功");
????}
????@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
"en"?xmlns:th="http://www.thymeleaf.org">
????"UTF-8">
????Index
????"@{css/index.css}"?rel="stylesheet"?type="text/css">
????"container">
????????"header">
????????????初級(jí)SpringBoot+Shiro小栗子?Node-One
????????????
????????
????????"main">
????????????"left">
????????????????"form-group">
????????????????????type="text"?name="username"?placeholder="請(qǐng)輸入用戶名">
????????????????
????????????????"form-group">
????????????????????type="password"?name="password"?placeholder="請(qǐng)輸入密碼">
????????????????
????????????????
????????????????
????????????
????????????"right">
????????????????"form-group">
????????????????????type="text"?name="username"?placeholder="請(qǐng)輸入用戶名">
????????????????
????????????????"form-group">
????????????????????type="password"?name="password"?placeholder="請(qǐng)輸入密碼">
????????????????
????????????????"form-group">
????????????????????type="text"?name="show"?placeholder="自我介紹">
????????????????
????????????????
????????????
????????
????
????
????????
????
home.html
"en"?xmlns:th="http://www.thymeleaf.org">
????"UTF-8">
????Home
????"@{css/index.css}"?rel="stylesheet"?type="text/css">
"container">
????
????"main">
????????"table">
????????????
????????????
????????????????Username
????????????????Password
????????????????Show
????????????
????????????
????????????
????????????"u?:?${users}">
????????????????[[${u.username}]]
????????????????[[${u.password}]]
????????????????[[${u.show}]]
????????????
????????????
????????
????
以上兩種配置各打包一次(記得留著打包好的jar包)
http://nginx.org/
解壓到無(wú)中文目錄,修改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://myapp;
????????????????proxy_set_header???Host?????????????$host;
????????????????proxy_set_header???X-Real-IP????????$remote_addr;
????????????????proxy_set_header???X-Forwarded-For??$proxy_add_x_forwarded_for;
????????????}
????}
到此,先啟動(dòng)兩個(gè)jar包(分別是8081,Node-One;8082,Node-Two)
然后啟動(dòng)Nginx
瀏覽器訪問(wèn):http://localhost/

?
?刷新看看..

?
?隨便在一個(gè)節(jié)點(diǎn)上注冊(cè),登錄,然后刷新到另外一個(gè)節(jié)點(diǎn),發(fā)現(xiàn)不用登錄就可以訪問(wèn)權(quán)限資源

?
?
?
?GitHub
https://github.com/Mysakura/boot-shiro-session
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
????????BaseResponse
????????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,"注冊(cè)成功");
????}
????@RequestMapping("/home")
????public?ModelAndView?home(){
????????ModelAndView?mv?=?new?ModelAndView("home");
????????mv.addObject("users",?userService.getUsers());
????????return?mv;
????}
}
粉絲福利:實(shí)戰(zhàn)springboot+CAS單點(diǎn)登錄系統(tǒng)視頻教程免費(fèi)領(lǐng)取
???
?長(zhǎng)按上方微信二維碼?2 秒 即可獲取資料
感謝點(diǎn)贊支持下哈?
