shiro+springboot使用
1、什么是shiro
shiro一款java安全框架,提供认证、授权、会话管理、加密等功能。
2、核心组件
subject:表示当前操作用户(包含用户、第三方进程、后台账户);代表了当前用户的安全操作
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过该组件来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: 当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
3、项目搭建
项目结构,使用idea创建springboot项目
jar包引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Apache Shiro所需的jar包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>1.2.4</version>
</dependency>
配置注解类
package com.example.demo.controller.shiro;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
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.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.apache.shiro.mgt.SecurityManager;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
* 权限认证,为当前登录的Subject授予角色和权限
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
//shiroFilter.setLoginUrl("/login");//未登录跳转
shiroFilter.setUnauthorizedUrl("/test1");//未授权跳转
LinkedHashMap<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");//未认证可登陆路劲
filterChainDefinitionMap.put("/*", "authc");//未认证拦截所有路径
shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilter;
}
/**
* 核心的安全事务管理器
*
*
* @return
*/
@Bean(name = "securityManager")
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
//设置realm
securityManager.setRealm( myShiroRealm( ) );
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* 身份认证Realm,此处的注入不可以缺少。否则会在UserRealm中注入对象会报空指针.
* @return
*/
@Bean
public ShiroDBRealm myShiroRealm( ){
ShiroDBRealm myShiroRealm = new ShiroDBRealm();
myShiroRealm.setCredentialsMatcher( hashedCredentialsMatcher() );
return myShiroRealm;
}
/**
* 哈希密码比较器。在myShiroRealm中作用参数使用
* 登陆时会比较用户输入的密码,跟数据库密码配合盐值salt解密后是否一致。
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用md5算法;
hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5( md5(""));
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
/**
* cookie管理对象;
*
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
cookieRememberMeManager.setCipherKey(Base64.decode("5aaC5qKm5oqA5pyvAAAAAA=="));
return cookieRememberMeManager;
}
/**
* cookie对象;
*
* @return
*/
@Bean
public SimpleCookie rememberMeCookie() {
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
// 记住我cookie生效时间1小时 ,单位秒
simpleCookie.setMaxAge(60 * 60 * 1 * 1);
simpleCookie.setPath("test");
simpleCookie.setHttpOnly(true);
return simpleCookie;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;否则@RequiresRoles等注解无法生效
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* Shiro生命周期处理器
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
/**
* 自动创建代理
* @return
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
}
创建realm类(继承AuthorizingRealm)
package com.example.demo.controller.shiro;
import com.example.demo.controller.entity.User;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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 java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ShiroDBRealm extends AuthorizingRealm {
final String username = "admin";//用户名
final String password = "d9be323985a51535f6f6c55750f23af5";//用户密码,使用123与wx加密得到
/**
*该方法身份认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取身份
String username = (String) authenticationToken.getPrincipal();
//模拟数据库查询
User user = queryUserByName(username);
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( user.getName(),
user.getPassword(), // 密码
ByteSource.Util.bytes(user.getSalt()),
getName());
return authenticationInfo;
}
/**
*用户授权认证
*调用时机,在使用Subject中的权限角色验证时,如checkPermission等
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set<String> roles = new HashSet<>();//角色集合
Set<String> set = new HashSet<String>();//权限集合
set.add("test");//添加权限
set.add("create");//添加权限
info.setStringPermissions(set);
System.out.print("权限添加成功");
return info;
}
/**
* 获取用户信息
* @param name
* @return
*/
public User queryUserByName(String name){
User user = new User();
user.setSalt("wx");
user.setId("1");
user.setName(username);
user.setPassword(password);
return user;
}
}
用户类
该类可自行创建,包含用户、角色、权限等类
加密工具类
package com.example.demo.controller.shiro;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
public class SalfUtil {
public static final String md5(String password, String salt){
//加密方式
String hashAlgorithmName = "MD5";
//盐:为了即使相同的密码不同的盐加密后的结果也不同
ByteSource byteSalt = ByteSource.Util.bytes(salt);
//密码
Object source = password;
//加密次数
int hashIterations = 2;
SimpleHash result = new SimpleHash(hashAlgorithmName, source, byteSalt, hashIterations);
return result.toString();
}
public static void main(String[] args) {
String str = md5("123", "wx");
System.out.print(str);
}
}
登陆控制controller
package com.example.demo.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class LogoInController {
/**
*登陆
*/
@RequestMapping("login")
public String login(String name, String password){
try {
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(name,password);
Subject currentUser = SecurityUtils.getSubject();//获取当前用户信息
currentUser.login(usernamePasswordToken);//登陆验证
System.out.print(currentUser);
System.out.print("Jinlai");
} catch (Exception e) {
e.printStackTrace();
return "error";
}
return "index";//静态页面
}
@RequestMapping("test")
@ResponseBody
public String test(){
try {
System.out.print("hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii");
} catch (Exception e) {
e.printStackTrace();
return "test访问失败";
}
return "test访问成功";
}
@RequestMapping("test1")
@ResponseBody
public String test1(){
try {
Subject currentUser = SecurityUtils.getSubject();
currentUser.checkPermission("create");
System.out.print("hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii");
} catch (Exception e) {
e.printStackTrace();
return "test1访问失败";
}
return "test1访问成功";
}
@RequestMapping("test2")
@RequiresPermissions("create")
@ResponseBody
public String test2(){
try {
// Subject currentUser = SecurityUtils.getSubject();
//currentUser.checkPermission("create");//验证是否有该权限
System.out.print("hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii");
} catch (Exception e) {
e.printStackTrace();
return "test2访问失败";
}
return "test2访问成功";
}
@RequestMapping("logout")
@ResponseBody
public String logout(){
try {
Subject currentUser = SecurityUtils.getSubject();//获取当前用户信息
currentUser.logout();
} catch (Exception e) {
e.printStackTrace();
return "退出失败";
}
return "退出成功";
}
public static void main(String[] args) {
try {
}catch (Exception e){
}
}
}