1.什么是shiro?
Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications.
Apache Shiro™是一个功能强大且易于使用的Java安全框架,它执行身份验证,授权,加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大的Web和企业应用程序。
Shiro提供了用于执行以下方面的应用程序安全性API(我将其称为应用程序安全性的4个基石):
身份验证-证明用户身份,通常称为用户“登录”。
授权-访问控制
密码术-保护或隐藏数据以防窥视
会话管理-每个用户的时间敏感状态
2.使用shiro的三个核心组件是什么?
三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
3.ShiroConfiguration类
package com.apache.shiroview.util;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfiguration {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map filterChainDefinitionMap = new LinkedHashMap();
shiroFilterFactoryBean.setLoginUrl("/showLogin");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
filterChainDefinitionMap.put("/login", "anon"); // 表示可以匿名访问
filterChainDefinitionMap.put("/userInfo/register", "anon"); // 注册表示可以匿名访问
filterChainDefinitionMap.put("/userInfo/doLogin", "anon"); // 注册表示可以匿名访问
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/resources/static/css/**", "anon"); // 表示可以匿名访问
filterChainDefinitionMap.put("/fonts/**", "anon"); // 表示可以匿名访问
filterChainDefinitionMap.put("/css/**", "anon");//不需要验证
filterChainDefinitionMap.put("/images/**", "anon"); // 表示可以匿名访问
filterChainDefinitionMap.put("/js/**", "anon"); // 表示可以匿名访问
filterChainDefinitionMap.put("/plugins/**", "anon"); // 表示可以匿名访问
filterChainDefinitionMap.put("/*", "authc");// 表示需要认证才可以访问
filterChainDefinitionMap.put("/**", "authc");// 表示需要认证才可以访问
filterChainDefinitionMap.put("/*.*", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); // 原来在这里
return myShiroRealm;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//散列算法
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName(PasswordHelper.ALGORITHM_NAME); // 散列算法
hashedCredentialsMatcher.setHashIterations(PasswordHelper.HASH_ITERATIONS); // 散列次数
return hashedCredentialsMatcher;
}
@Bean
public PasswordHelper passwordHelper() {
return new PasswordHelper();
}
}
4.PasswordHelper
package com.apache.shiroview.util;
import com.apache.shiroview.domain.UserInfoModel;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
public class PasswordHelper {
private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
public static final String ALGORITHM_NAME = "md5"; // 基础散列算法
public static final int HASH_ITERATIONS = 2; // 自定义散列次数
public void encryptPassword(UserInfoModel user){
// 随机字符串作为salt因子,实际参与运算的salt我们还引入其它干扰因子
user.setSalt(randomNumberGenerator.nextBytes().toHex());
String newPassword = new SimpleHash(ALGORITHM_NAME, user.getPassword(),
ByteSource.Util.bytes(user.getCredentialsSalt()), HASH_ITERATIONS).toHex();
user.setPassword(newPassword);
}
}
5.MyShiroRealm
/**
* Copyright 2018 Goldwind Science & Technology.
* All rights reserved. GOLDWIND PROPRIETARY/CONFIDENTIAL.
* Use is subject to license terms.
*/
package com.apache.shiroview.util;
import com.apache.shiroview.domain.PermissionModel;
import com.apache.shiroview.domain.RoleModel;
import com.apache.shiroview.domain.UserInfoModel;
import com.apache.shiroview.domain.UserModel;
import com.apache.shiroview.service.UserInfoService;
import com.apache.shiroview.service.UserService;
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 org.springframework.beans.factory.annotation.Autowired;
import java.util.Collection;
/**
* 身份校验核心类
*
* @author Administrator
*
*/
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserInfoService infoService ;
/**
* 认证信息(身份验证) Authentication 是用来验证用户身份
*
* 输入 认证信息
*
* 返回
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("身份认证-------------》doGetAuthenticationInfo");
String username = (String) token.getPrincipal();
UserInfoModel user = infoService.findUserByName(username);
if (user == null) {
return null;
}
// 获取用户的输入帐号
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUserName(), // 用户名
user.getPassword(), ByteSource.Util.bytes(user.getCredentialsSalt()), getName());
return authenticationInfo;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
// 获取当前用户
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
String username = (String) principals.getPrimaryPrincipal();
UserInfoModel user = infoService.findUserByName(username);
for (RoleModel role : user.getRoles()) {
authorizationInfo.addRole(role.getRoleName());
for (PermissionModel permission : role.getPermissList()) {
authorizationInfo.addStringPermission(permission.getAuthName());
}
}
return authorizationInfo;
}
@Override
public boolean hasAllRoles(PrincipalCollection principal, Collection<String> roleIdentifiers) {
AuthorizationInfo info = getAuthorizationInfo(principal);
return info != null && hasAnyRoles(roleIdentifiers, info);
}
private boolean hasAnyRoles(Collection<String> roleIdentifiers, AuthorizationInfo info) {
if (roleIdentifiers != null && !roleIdentifiers.isEmpty()) {
for (String roleName : roleIdentifiers) {
if (hasRole(roleName, info)) {
return true;
}
}
return false;
}
return true;
}
}
6.UserInfoController
package com.apache.shiroview.controller;
import com.apache.shiroview.domain.UserInfoModel;
import com.apache.shiroview.service.UserInfoService;
import com.apache.shiroview.util.PasswordHelper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.*;
@Controller
@RequestMapping("/userInfo")
public class UserInfoController {
@Autowired
private PasswordHelper passwordHelper;
@Autowired
private UserInfoService userInfoService ;
@RequestMapping("showLogin")
public ModelAndView showLogin(){
ModelAndView modelAndView = new ModelAndView("login");
return modelAndView;
}
@GetMapping("doLogin")
@ResponseBody
public ModelAndView doLogin(@RequestParam String username, @RequestParam String password) {
ModelAndView modelAndView = new ModelAndView();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//实现记住我
token.setRememberMe(true);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
} catch (IncorrectCredentialsException ice) {
modelAndView.addObject("result", "密码错误");
modelAndView.setViewName("login");
return modelAndView;
} catch (UnknownAccountException uae) {
modelAndView.addObject("result", "用户不存在");
modelAndView.setViewName("login");
return modelAndView;
}
UserInfoModel user = userInfoService.findUserByName(username);
subject.getSession().setAttribute("user", user);
modelAndView.setViewName("index"); ;
return modelAndView;
}
@GetMapping("register")
@ResponseBody
public Integer register(@RequestParam String username, @RequestParam String password) {
UserInfoModel user = new UserInfoModel();
user.setId(UUID.randomUUID().toString().replaceAll("-",""));
user.setUserName(username);
user.setPassword(password);
int index = 0 ;
passwordHelper.encryptPassword(user);
try {
userInfoService.saveUser(user);
index = 1 ;
} catch (Exception e) {
e.printStackTrace();
index = -1 ;
}
return index;
}
}