本章节基于:五、Springboot 整合Shiro---03认证---第三方QQ登陆
一、通过realm进行权限控制
1、在templates下创建三个html页面
user.html、admin.html、unauthorized.html
2、创建一个Action类
package com.xslde.action;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Map;
/**
* Created by xslde on 2018/7/21
*/
@Controller
public class PermissionAction {
@GetMapping("/unauthorized")
public String unauthorized(){
return "unauthorized.html";
}
//拥有user角色才可访问
@GetMapping("/user")
public String user(Map<String,String> mode){
mode.put("msg","拥有user角色");
return "user.html";
}
//拥有user角色才可访问和user:query权限才可访问
@GetMapping("/user/per")
public String userPer(Map<String,String> mode){
mode.put("msg","拥有user角色和user:query权限");
return "user.html";
}
//拥有admin角色才可访问
@GetMapping("/admin")
public String admin(Map<String,String> mode){
mode.put("msg","拥有admin角色");
return "admin.html";
}
}
3、在ShiroConf.class中加入上面action类中的请求url权限控制,对shiroFilter方法进行改动,添加拦截url和无权访问跳转页面url
package com.xslde.configurer;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.session.mgt.SessionManager;
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.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @Author xslde
* @Description
* @Date 2018/7/20 16:25
*/
@Configuration
public class ShiroConf {
//注入shiro过滤器
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilter(WebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setSuccessUrl("/index");// 登录成功后要跳转的链接
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");//设置无权限跳转页面
Map<String, String> chains = new LinkedHashMap<>();
chains.put("/logout","logout");//登出
chains.put("/login", "anon");//anon表示可以匿名访问
chains.put("/login/qq", "anon");//anon表示可以匿名访问
chains.put("/authorize/qq", "anon");//anon表示可以匿名访问
//对PermissionAction.class 中的url进行权限控制
chains.put("/user", "roles[user]");//需要user角色才可以访问
chains.put("/user/per", "perms[user:query]");//需要user角色才可以访问
chains.put("/admin", "roles[admin]");//需要admin角色才可以访问
//chains.put("/**", "authc");//表示需要认证,才能访问
chains.put("/**", "user");//表示需要认证或记a住我都能访问
shiroFilterFactoryBean.setFilterChainDefinitionMap(chains);
return shiroFilterFactoryBean;
}
//安全管理其
@Bean
public WebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(shiroRealm());
securityManager.setCacheManager(cacheManager());
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
//会话管理器
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionIdUrlRewritingEnabled(true);
sessionManager.setGlobalSessionTimeout(1 * 60 * 60 * 1000);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionIdCookie(rememberMeCookie());
return sessionManager;
}
//Realm,里面是自己实现的认证和授权业务逻辑
@Bean
public ShiroRealm shiroRealm() {
ShiroRealm shiroRealm = new ShiroRealm();
shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return shiroRealm;
}
//缓存管理
@Bean
public EhCacheManager cacheManager() {
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return cacheManager;
}
//密码管理
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("md5"); //散列算法使用md5
credentialsMatcher.setHashIterations(2); //散列次数,2表示md5加密两次
credentialsMatcher.setStoredCredentialsHexEncoded(true);//启用十六进制存储
return credentialsMatcher;
}
//cookie管理
@Bean
public SimpleCookie rememberMeCookie() {
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setHttpOnly(true);
cookie.setMaxAge(1 * 60 * 60);
return cookie;
}
//记住我
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//这个地方有点坑,不是所有的base64编码都可以用,长度过大过小都不行,没搞明白,官网给出的要么0x开头十六进制,要么base64
cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
return cookieRememberMeManager;
}
}
4、在ShiroRealm.class 中添加admin角色用户,并在权限控制doGetAuthorizationInfo()方法中添加用户权限控制
package com.xslde.configurer;
import com.xslde.model.mapped.User;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
/**
* @Author xslde
* @Description
* @Date 2018/7/20 16:30
*/
public class ShiroRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//给当前用户授权的权限(功能权限、角色)
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//xslde用户拥有user角色
User user = (User) principals.getPrimaryPrincipal();
//真实开发中,角色权限从数据库获取
if (user.getUsername().equals("xslde")){
//设置该用户拥有user角色
authorizationInfo.addRole("user");
//设置该用户拥有delete权限
authorizationInfo.addStringPermission("user:query");
}
//admin用户拥有admin角色
if (user.getUsername().equals("admin")){
//设置该用户拥有user角色
authorizationInfo.addRole("admin");
//设置该用户拥有delete权限
authorizationInfo.addStringPermission("admin:delete");
}
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户名
String username = (String) token.getPrincipal();
//开发中,这里都是去数据库查询
//做demo,就不查询了
if (!"xslde".equals(username)&&!"test".equals(username)&&!"xslde.com".equals(username)&&!"admin".equals(username)){
throw new UnknownAccountException("用户不存在!");
}
User user =null;
if ("xslde".equals(username)){
user = new User();
user.setUsername("xslde");
user.setPassword("0caf568dbf30f5c33a13c56b869259fc");
user.setSalt("abcd");
user.setAvailable(1);
}
if ("admin".equals(username)){
user = new User();
user.setUsername("admin");
user.setPassword("0caf568dbf30f5c33a13c56b869259fc");
user.setSalt("abcd");
user.setAvailable(1);
}
if ("test".equals(username)){
user = new User();
user.setUsername("test");
user.setPassword("0caf568dbf30f5c33a13c56b869259fc");
user.setSalt("abcd");
user.setAvailable(0);
}
//这是模拟数据库里面拥有QQ第三方用户信息
if ("xslde.com".equals(username)){
user = new User();
user.setUsername("xslde.com");
user.setAvailable(1);
user.setSalt("abcd");
user.setPassword("6e20337c6b222fa0a8c3bbb9dd979374");//
}
if (user.getAvailable()!=1){
throw new LockedAccountException("账户已被锁定");
}
return new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());
}
//生成一个加盐密码
public static void main(String[] args) {
String hashAlgorithmName = "md5";//加密类型
Integer iteration = 2;//迭代次数
String password = "123456";
String salt = "abcd";
String s = new SimpleHash(hashAlgorithmName,password,salt,iteration).toHex();
System.out.println(s);
//加密后的密码
//0caf568dbf30f5c33a13c56b869259fc
}
}
完成以上步骤后,启动项目使用admin登陆
单击需要user角色的页面:
显示为该页面,说明权限控制已生效,接下来访问需要admin角色的页面:
推出登陆,换角色为user的"xslde"用户:
单击需要user角色用的页面:
到此url控制授权完成。
二、通过Shiro注解进行权限控制
1、开启注解权限控制功能
在pom文件中添加aop依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在application.yml文件中配置开启aop代理:
spring:
aop:
#开启aop代理
auto: true
proxy-target-class: true
在ShiroConf.class中添加:
//开启shiro注解权限控制
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
attributeSourceAdvisor.setSecurityManager(securityManager);
return attributeSourceAdvisor;
}
在PermissionAction.class中添加几个访问方法,测试注解权限控制是否启用:
//通过注解控制授权
@RequiresRoles({"admin"})
@GetMapping("/abc")
public String abc(Map<String,String> mode){
mode.put("msg","拥有admin角色,并且是通过注解控制");
return "admin.html";
}
//通过注解控制权限
@RequiresPermissions({"user:query"})
@GetMapping("/abcd")
public String abcd(Map<String,String> mode){
mode.put("msg","拥有user:query权限,并且是通过注解控制");
return "user.html";
}
2、测试注解是否生效:
启动项目:
注解控制权限生效:
使用admin角色用户访问:
Shiro还有两种控制方式就不记录了,个人不怎么用:
方式3:标签控制
方式4:编程控制
权限控制到这里就完成了。
项目实例:springboot-example06