一、表设计
权限表大体分为三个表:用户表、角色表、权限表,以及用户角色中间表、角色权限表。对应关系是用户角色多对多,角色权限多对多。这只是简单基本的表设计,可以根据需求自己设计。
二、定制realm
package com.shiro.common;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UsernamePasswordToken;
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.springframework.beans.factory.annotation.Autowired;
import com.shiro.dao.PermissionMapper;
import com.shiro.dao.RoleMapper;
import com.shiro.dao.UserMapper;
import com.shiro.entity.Permission;
import com.shiro.entity.Role;
import com.shiro.entity.User;
public class MyShiroRealm extends AuthorizingRealm{
@Autowired
private UserMapper usermapper;
@Autowired
private RoleMapper rolemapper;
@Autowired
private PermissionMapper permissionmapper;
//每个realm都有一个名字
static String REALM_NAME="myrealm";
/**
* 支持哪种令牌
*/
@Override
public boolean supports(AuthenticationToken token) {
// TODO Auto-generated method stub
return token instanceof UsernamePasswordToken;
}
/**
* 获取权限过程
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取用户名
String userName=principals.getPrimaryPrincipal().toString();
User user=usermapper.getUserByName(userName.trim());
//构建权限的类
SimpleAuthorizationInfo sai=new SimpleAuthorizationInfo();
Set<String> proleList=new HashSet<String>();
Set<String> stringPermissions=new HashSet<String>();
if(user!=null){
List<Role> lrole = rolemapper.getRoleById(user.getUser_id());
for (Role role : lrole) {
proleList.add(role.getName());
List<Permission> plist = permissionmapper.getPermissionById(role.getId());
for (Permission permission : plist) {
stringPermissions.add(permission.getName());
}
}
}
sai.setRoles(proleList);
sai.setStringPermissions(stringPermissions);
return sai;
}
/**
* 认证过程
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upt=(UsernamePasswordToken)token;
String userName=token.getPrincipal().toString();
String password=String.valueOf(upt.getPassword());
User user=usermapper.getUserByName(userName.trim());
if(user!=null){
String realPwd=user.getPassword();
if(realPwd.equals(password)){
SimpleAccount sa=new SimpleAccount(userName,password,"REALM_NAME");
return sa;
}
}
return null;
}
}
三、shiro配置类
package com.shiro.common;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import org.apache.shiro.realm.Realm;
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.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.filter.DelegatingFilterProxy;
@Configuration
public class ShiroConfigBean {
/*
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
* @return
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Autowired org.apache.shiro.mgt.SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public FilterRegistrationBean webShiroFilter(){
FilterRegistrationBean frb=new FilterRegistrationBean();
DelegatingFilterProxy dfp=new DelegatingFilterProxy();
frb.setFilter(dfp);
frb.setName("shiroFilter");
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
linkedHashSet.add("/*");
frb.setUrlPatterns(linkedHashSet);
Map<String, String> initParameters=new HashMap<String, String>();
initParameters.put("targetFilterLifecycle", "true");
frb.setInitParameters(initParameters);
return frb;
}
/**
* 配置我的realm
* @return
*/
@Bean
public Realm myRealm(){
return new MyShiroRealm();
}
/**
* 定義默認的securityManager
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(@Autowired Realm myRealm){
DefaultWebSecurityManager dwm=new DefaultWebSecurityManager();
dwm.setRealm(myRealm);
return dwm;
}
/**
* 定義和過濾器一致名字的ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(@Autowired org.apache.shiro.mgt.SecurityManager securityManager){
ShiroFilterFactoryBean sffb=new ShiroFilterFactoryBean();
sffb.setSecurityManager(securityManager);
sffb.setLoginUrl("/login.html");
sffb.setUnauthorizedUrl("/faliure.html");
Map<String, String> urls=new HashMap<String, String>();
urls.put("/login", "anon");
urls.put("/succeed", "authc");
urls.put("/data", "roles[role1]");
sffb.setFilterChainDefinitionMap(urls);
return sffb;
}
/**
* 定義後置處理器
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
}
四、登录以及权限限制
package com.shiro.controller;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
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;
@Controller
public class LoginController {
@RequestMapping("/getlogin")
public String getLogin(){
return "login";
}
@RequestMapping("/exit")
public String exit(){
Subject currentUser = SecurityUtils.getSubject();
currentUser.logout();
return "login";
}
@RequestMapping("/toData")
public String toData(){
return "data";
}
@RequestMapping("/login")
public String login(String username,String password,HttpServletRequest request){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken upt=new UsernamePasswordToken(username,password);
try {
subject.login(upt);
/*subject.getSession().setAttribute("userInfo","");
//关键代码 shiro自动保存了上一次请求的地址 只需要获取并重新跳转即可
//可以使用WebUtils.issueRedirect重定向跳转
SavedRequest savedRequest = WebUtils.getSavedRequest(request);
if(savedRequest!=null)
return "redirect:"+savedRequest.getRequestURI()+"?"+savedRequest.getQueryString();*/
return "succeed";
} catch (AuthenticationException e) {
return "failure";
}
}
@RequiresPermissions({"query"} )
@RequestMapping("/queryTest")
@ResponseBody
public String queryTest(){
return "0";
}
@RequiresPermissions({"insert"} )
@RequestMapping("/insertTest")
@ResponseBody
public String insertTest(){
return "0";
}
@RequiresPermissions({"update"} )
@RequestMapping("/updateTest")
@ResponseBody
public String updateTest(){
return "0";
}
@RequiresPermissions({"delete"} )
@RequestMapping("/deletTest")
@ResponseBody
public String deletTest(){
return "0";
}
}
其余代码省略,大概就是查询权限的。
附上权限认证所有注解:
@RequiresAuthentication
验证用户是否登录,等同于方法subject.isAuthenticated() 结果为true时。
@RequiresUser
验证用户是否被记忆,user有两种含义:
一种是成功登录的(subject.isAuthenticated() 结果为true);
另外一种是被记忆的(subject.isRemembered()结果为true)。
@RequiresGuest
验证是否是一个guest的请求,与@RequiresUser完全相反。
换言之,RequiresUser == !RequiresGuest。
此时subject.getPrincipal() 结果为null.
@RequiresRoles
例如:@RequiresRoles("aRoleName");
void someMethod();
如果subject中有aRoleName角色才可以访问方法someMethod。如果没有这个权限则会抛出异常AuthorizationException。
@RequiresPermissions
例如: @RequiresPermissions({"file:read", "write:aFile.txt"} )
void someMethod();
要求subject中必须同时含有file:read和write:aFile.txt的权限才能执行方法someMethod()。否则抛出异常AuthorizationException。
转自https://www.cnblogs.com/wudage/p/7305003.html
四、运行效果