写一个不花里胡哨的纯粹的Springboot+Shiro的入门小栗子

效果如图:

首页:有登录注册

SpringBoot+Shiro入门小栗子-LMLPHP

先注册一个,然后登陆

SpringBoot+Shiro入门小栗子-LMLPHP

登录,成功自动跳转到home页

SpringBoot+Shiro入门小栗子-LMLPHP

home页:通过认证之后才可以进

SpringBoot+Shiro入门小栗子-LMLPHP


代码部分:

依赖:

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion> <groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>demo</name>
<description>Demo project for Spring Boot</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-all -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.5</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

Java配置类:

package com.example.demo.conf;

import com.example.demo.auth.PermissionRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
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 java.util.LinkedHashMap; /**
* @program: boot-shiro
* @description:
* @author: 001977
* @create: 2018-07-17 18:22
*/
@Configuration
public class ShiroConfig { /**
* 1. 配置SecurityManager
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm());
return securityManager;
} /**
* 2. 配置缓存
* @return
*/
@Bean
public CacheManager cacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return ehCacheManager;
} /**
* 3. 配置Realm
* @return
*/
@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;
} /**
* 4. 配置LifecycleBeanPostProcessor,可以来自动的调用配置在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<String, String> map = new LinkedHashMap<>();
// 静态资源
map.put("/css/**", "anon");
map.put("/js/**", "anon"); // 公共路径
map.put("/login", "anon");
map.put("/register", "anon");
//map.put("/*", "anon"); // 登出,项目中没有/logout路径,因为shiro是过滤器,而SpringMVC是Servlet,Shiro会先执行
map.put("/logout", "logout"); // 授权
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());
// 配置权限路径
factoryBean.setFilterChainDefinitionMap(map);
// 配置登录url
factoryBean.setLoginUrl("/");
// 配置无权限路径
factoryBean.setUnauthorizedUrl("/unauthorized");
return factoryBean;
} }

Realm类:

package com.example.demo.auth;

import com.example.demo.common.entity.User;
import com.example.demo.service.UserService;
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.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired; import java.util.HashSet;
import java.util.Set; /**
* @program: boot-shiro
* @description:
* @author: 001977
* @create: 2018-07-12 13:03
*/
public class PermissionRealm extends AuthorizingRealm { @Autowired
private UserService userService; @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Object principal = principalCollection.getPrimaryPrincipal();
User user = (User) principal;
Set<String> roles = new HashSet<>();
roles.add("user");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
return info;
} @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken uToken = (UsernamePasswordToken) authenticationToken; String username = uToken.getUsername();
String password = String.valueOf(uToken.getPassword()); User user = userService.login(new User(username,password)); if(user == null){
throw new AuthenticationException("用户名密码不存在");
}
//认证的实体信息
Object principal = user;
//从数据库获取的密码
Object hashedCredentials = user.getPassword();
//盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());
//当前Realm对象的name,调用父类的getName方法
String realmName = getName(); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realmName); return info;
}
}

Controller:

package com.example.demo.controller;

import com.example.demo.common.TempStorage;
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; /**
* @program: boot-shiro
* @description:
* @author: 001977
* @create: 2018-07-12 13:02
*/
@RestController
public class SimpleController { @Autowired
private UserService userService; @RequestMapping("/")
public ModelAndView index(){
return new ModelAndView("index");
} @RequestMapping("/login")
public BaseResponse<String> login(@RequestBody User user){
BaseResponse<String> 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", TempStorage.getInstance().getMap());
return mv;
}
}

其余代码参见GitHub

05-11 09:30