当我们开发一个springboot项目,建议
登陆控制和权限控制,不要自己手动写代码验证和拦截器写安全拦截,
可以统一使用shiro框架
先添加依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
一共需要新建两个文件
- ShiroConfig
import java.util.LinkedHashMap;
import java.util.Map;
import com.hjr.shiro.MyShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
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.mgt.SecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfig {
/**
* 凭证匹配器
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//md5加密1次
hashedCredentialsMatcher.setHashAlgorithmName("md5");
hashedCredentialsMatcher.setHashIterations(1);
return hashedCredentialsMatcher;
}
/**
* 自定义realm
*
* @return
*/
@Bean
public MyShiroRealm userRealm() {
MyShiroRealm userRealm = new MyShiroRealm();
userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return userRealm;
}
/**
* 核心的安全事务管理器
* @return
*/
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager ();
//设置realm
securityManager.setRealm(userRealm());
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* cookie管理对象;
* rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager(){
//System.out.println("ShiroConfiguration.rememberMeManager()");
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
return cookieRememberMeManager;
}
/**
* cookie对象;
* rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等。
* @return
*/
@Bean
public SimpleCookie rememberMeCookie(){
//System.out.println("ShiroConfiguration.rememberMeCookie()");
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//<!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
/**
* 设置过滤规则
*
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
shiroFilterFactoryBean.setLoginUrl("/notLogin");
// 设置无权限时跳转的 url;
shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");
// 设置拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//游客,开发权限
filterChainDefinitionMap.put("/guest/**", "anon");
//用户,需要角色权限 “user”
filterChainDefinitionMap.put("/user/**", "roles[user]");
//管理员,需要角色权限 “admin”
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//开放登陆接口
filterChainDefinitionMap.put("/login", "anon");
//其余接口一律拦截
//主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
System.out.println("Shiro拦截器工厂类注入成功");
return shiroFilterFactoryBean;
}
}
- MyShiroRealm
import com.hjr.admin.system.resource.mapper.ResourceMapper;
import com.hjr.admin.system.user.mapper.UserMapper;
import com.hjr.admin.system.user.model.UserModel;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MyShiroRealm extends AuthorizingRealm {
private static final Logger LOGGER = LoggerFactory.getLogger(UserModel.class);
protected static UserMapper userMapper = new UserMapper() ;
protected static ResourceMapper resourceMapper = new ResourceMapper() ;
/**
* 权限授权
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
UserModel sysUser = (UserModel) principals.getPrimaryPrincipal();
List<String> sysPermissions = resourceMapper.queryForListByChaId(sysUser.getId());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(sysPermissions);
LOGGER.info("=====================================================================doGetAuthorizationInfo");
return info;
}
/**
* 登录认证
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
UserModel userModel = new UserModel();
String password = "123456";
String hashAlgorithmName = "MD5";
String credentials = "123456";
int hashIterations = 1;
Object obj = new SimpleHash(hashAlgorithmName, credentials, "yanzhi", hashIterations);
System.out.println(obj);
userModel.setPassword(String.valueOf(obj));
// if (sysUser == null) {
// return null;
// }
LOGGER.info("===============================================================222222222222222222222");
}
shiro的功能分为登录认证与权限检测,权限检测只有在登录认证成功之后才有效。否则你所有的请求都会被跳转到 shiroFilterFactoryBean.setLoginUrl("/notLogin");
登录认证,需要先写一个接口并访问,参数为username和password
// 从SecurityUtils里边创建一个 subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 执行认证登陆
subject.login(token);
//根据权限,指定返回数据
String role = userMapper.getRole(username);
if ("user".equals(role)) {
return resultMap.success().message("欢迎登陆");
}
if ("admin".equals(role)) {
return resultMap.success().message("欢迎来到管理员页面");
}
return resultMap.fail().message("权限错误!");
在登录成功后才可以进行权限验证
重点
- 一共需要新建两个文件
- 权限检测只有在登录认证成功之后才有效,需要先写一个接口并访问,参数为username和password,登陆成功后才能测试权限检测功能