<!--集成shiro安全框架-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
Shiro 配置类
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/*拦截器*/
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
/*配置不会被拦截的链接 顺序判断*/
/*anon:所有url都都可以匿名访问*/
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/templates/**", "anon");
/*配置退出*/
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/index", "anon");
/*过滤链定义,从上向下顺序执行,一般将/**放在最为下*/
/*authc:所有url都必须认证通过才可以访问-->*/
filterChainDefinitionMap.put("/**", "authc");
/*如果不设置默认会自动寻找Web工程根目录下的"/login"页面*/
shiroFilterFactoryBean.setLoginUrl("/index");
/* 登录成功后要跳转的链接*/
shiroFilterFactoryBean.setSuccessUrl("/userInfo");
/*未授权界面*/
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 凭证匹配器(由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了)
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2000);//散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}
@Bean
public ShiroRealm myShiroRealm(){
ShiroRealm myShiroRealm = new ShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
mappings.setProperty("UnauthorizedException","403");
r.setExceptionMappings(mappings); // None by default
r.setDefaultErrorView("error"); // No default
r.setExceptionAttribute("ex"); // Default is "exception"
r.setWarnLogCategory("example.MvcLogger"); // No default
return r;
}
}
ShiroRealm
public class ShiroRealm extends AuthorizingRealm{
@Autowired
private ISysUserService iSysUserService; //用户
@Autowired
private ISysRoleService iSysRoleService; //角色
@Autowired
private ISysRoleMenuService iSysRoleMenuService;//角色-菜单
@Autowired
ISysMenuPermissionsService iSysMenuPermissionsService;//菜单-权限
/*权限授权*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
log.info("pc权限授权");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//用户
SysUser sysUser = (SysUser) super.getAvailablePrincipal(principals);
QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
sysRoleQueryWrapper.eq("idsys_role",sysUser.getSysRoleIdsysRole());
//角色
List<SysRole> sysRoleList = iSysRoleService.list(sysRoleQueryWrapper);
for (SysRole sysRole : sysRoleList) {
simpleAuthorizationInfo.addRole(sysRole.getSysRoleName());
//角色-菜单
QueryWrapper<SysRoleMenu> roleMenuQueryWrapper=new QueryWrapper<>();
roleMenuQueryWrapper.eq("sys_role_menu_roleId",sysUser.getSysRoleIdsysRole());
List<SysRoleMenu> SysRoleMenuList = iSysRoleMenuService.list(roleMenuQueryWrapper);
for (SysRoleMenu sysRoleMenu:SysRoleMenuList) {
//菜单-权限 shirokey
QueryWrapper<SysMenuPermissions> sysMenuPermissionsQueryWrapper = new QueryWrapper<>();
sysMenuPermissionsQueryWrapper.eq("sys_menu_permissions_menuId",sysRoleMenu.getSysRoleMenuMenuid());
List<SysMenuPermissions> sysMenuPermissionsList = iSysMenuPermissionsService.list(sysMenuPermissionsQueryWrapper);
for (SysMenuPermissions sysMenuPermissions : sysMenuPermissionsList) {
if(!CheckUtil.isNull(sysMenuPermissions.getSysMenuPermissionsShirokey())) {
//simpleAuthorizationInfo.setStringPermissions(sysMenuList);
simpleAuthorizationInfo.addStringPermission(sysMenuPermissions.getSysMenuPermissionsShirokey());//添加权限标识
}
}
}
}
return simpleAuthorizationInfo;
}
/*登录认证*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
log.info("pc登录认证");
//获取用户的输入的账号.
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = String.valueOf(usernamePasswordToken.getPassword());
//根据用户名查询,用户名必须是唯一
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("sys_user_name", username);
SysUser sysUser = iSysUserService.getOne(queryWrapper);
//校验密码
//加密方式
String algorithmName = "MD5";
//加密次数
int hashIterations = 2000;
//加密盐值 username作为颜值必须为唯一值 注册时需要注意
Object salt = ByteSource.Util.bytes(sysUser.getSysUserName());;
/*md5Result:9ec808d39c36c800591f1ee14f5f3175*/
String md5Result = new SimpleHash(algorithmName, password, salt, hashIterations).toHex();
//判断用户密码是否正确,状态等
if (sysUser != null) {
if (md5Result.equals(sysUser.getSysUserPassword())) {
/*session用户*/
Session session = Jurisdiction.getSession();
session.setAttribute(username + Const.SESSION_USER,sysUser);
/*通过身份验证*/
/*principal:认证信息,可以是username,也可以是整个实体*/
Object principal = sysUser;
/*credentials:密码*/
Object credentials = sysUser.getSysUserPassword();
/*credentialsSalt:盐值*/
ByteSource credentialsSalt = ByteSource.Util.bytes(sysUser.getSysUserName());
/*realmName:当前realm对象的name,调用父类getName()*/
String realmName = getName();
SimpleAuthenticationInfo simpleAuthorizationInfo = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
return simpleAuthorizationInfo;
}
}
return null;
}
}
Controller
@Slf4j
@Controller
public class HomeController{
@Autowired
private UserInfoMapper userInfoMapper;
@Autowired
private TUserMapper tUserMapper;
@RequestMapping({"/","/index"})
public String index(){
Wrapper<UserInfo> wrapper=new QueryWrapper<>();
((QueryWrapper<UserInfo>) wrapper).eq("user_name","admin");
UserInfo userInfo = userInfoMapper.selectOne(wrapper);
log.info(userInfo.toString());
return"/login";
}
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(HttpServletRequest request, @RequestParam Map<String, Object> map) throws Exception{
UsernamePasswordToken token = new UsernamePasswordToken("admin", "123");
Subject subject = SecurityUtils.getSubject();
String msg = "";
try {
subject.login(token);
} catch (IncorrectCredentialsException ice) {
msg = "捕获密码错误异常";
} catch (UnknownAccountException uae) {
msg = "捕获未知用户名异常";
} catch (ExcessiveAttemptsException eae) {
msg = "重复多次登录";
}
map.put("msg", msg);
// 此方法不处理登录成功,由shiro进行处理
return "/userInfo";
}
@RequestMapping("/403")
public String unauthorizedRole(){
System.out.println("------没有权限-------");
return "403";
}
@RequiresPermissions("userInfo")
@RequestMapping("/userInfo")
public String userInfo(){
// Subject subject = SecurityUtils.getSubject();
// subject.hasRole("user");
return "userInfo";
}
@RequiresPermissions("userInfoAdd")
@RequestMapping("/userInfoAdd")
public String userInfoAdd(){
return "userInfoAdd";
}
@RequestMapping("/userInfoDel")
public String userInfoDel(){
return "userInfoDel";
}
}
**大功告成,下面是演示 **
http://127.0.0.1:9001/index
返回通过身份验证的simpleAuthorizationInfo,登录成功
访问 http://127.0.0.1:9001/userInfo
authorizationInfo.addStringPermission(“userInfoAdd”);
因为只加了authorizationInfo只加了 userInfoAdd 权限,没有 addStringPermission(“userInfo”);
而userInfo方法 又加了 @RequiresPermissions(“userInfo”)
所以只会跳转到 403 页面
访问 http://127.0.0.1:9001/userInfoAdd
authorizationInfo.addStringPermission(“userInfoAdd”);
userInfoAdd 又加了 @RequiresPermissions(“userInfoAdd”)
所以只跳转到 userInfoAdd 页面
请求都会进入 doGetAuthorizationInfo 进行权限校验
没有
@RequiresPermissions("请求)
或者
Subject subject = SecurityUtils.getSubject();
subject.hasRole(“user”);
则视为无须权限
http://127.0.0.1:9001/userInfoDel
也可以访问
且无需进入 doGetAuthorizationInfo
当我们登录成功后,其他操作
Request.Headers
将自动带上凭证
Cookie: JSESSIONID=ABD4BED200D6ACF452AB2373F916C93D
一个简单的微服务网站就搭建成功了。配合 Mubatis-Plus 使用,其他就是业务 上的问题了。