使用shiro对登陆进行权限验证,以及实现权限的动态管理。
数据库表
shiro配置文件
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.2.xsd">
/index.jsp=anon
/user/update!initAuth=anon
/baseUtils/update!changePermissions=anon
/**=authc
jdbc配置文件
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://127.0.0.1:3306/test
mysql.username=root
mysql.password=123456
#\u5B9A\u4E49\u521D\u59CB\u8FDE\u63A5\u6570
mysql.initialSize=0
#\u5B9A\u4E49\u6700\u5927\u8FDE\u63A5\u6570
mysql.maxActive=20
#\u5B9A\u4E49\u6700\u5927\u7A7A\u95F2
mysql.maxIdle=20
#\u5B9A\u4E49\u6700\u5C0F\u7A7A\u95F2
mysql.minIdle=1
#\u5B9A\u4E49\u6700\u957F\u7B49\u5F85\u65F6\u95F4
mysql.maxWait=60000
redis.pool.maxActive=8
redis.pool.maxIdle=8
redis.pool.maxWaitTime=3000
redis.pool.testOnBorrow=false
redis.host.ip=localhost
redis.host.port=6379
shiro.session.timeout=10000
redis.pass=admin
mybatis配置文件
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
springMVC配置文件
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
spring配置文件
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
dao层
package com.cn.hnust.dao;
import java.util.List;
import com.cn.hnust.pojo.UrlFilter;
public interface UrlFilterMapper {
List
void insertPermissions(UrlFilter urlFilter);
}
id,url,name,roles,permissions,sort,available
INSERT INTO t_url_permissions(url,name,roles,permissions,sort,available)
VALUES(#{url,jdbcType=VARCHAR},#{name,jdbcType=VARCHAR},#{roles,jdbcType=VARCHAR},
#{permissions,jdbcType=VARCHAR},
#{sort,jdbcType=INTEGER},#{available,jdbcType=VARCHAR})
package com.cn.hnust.dao;
import com.cn.hnust.pojo.User;
public interface IUserDao {
User selectByPrimaryKey(Integer userId);
User selectByUsername(String name);
}
id,user_name, password ,age
POJO实体类
package com.cn.hnust.pojo;
import java.io.Serializable;
public class UrlFilter implements Serializable{
/**
*
*/
private static final long serialVersionUID = 2725744448169512486L;
private Long id;
//地址描述
private String name;
//地址
private String url;
//所需角色
private String roles;
//所需权限
private String permissions;
//是否启用
private String available;
//排序
private String sort;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
this.roles = roles;
}
public String getPermissions() {
return permissions;
}
public void setPermissions(String permissions) {
this.permissions = permissions;
}
public String getAvailable() {
return available;
}
public void setAvailable(String available) {
this.available = available;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSort() {
return sort;
}
public void setSort(String sort) {
this.sort = sort;
}
}
package com.cn.hnust.pojo;
public class User {
private Integer id;
private String userName;
private String password;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
service层
package com.cn.hnust.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.cn.hnust.dao.UrlFilterMapper;
import com.cn.hnust.pojo.UrlFilter;
import com.cn.hnust.service.UrlFilterService;
@Service
public class UrlFilterServiceImpl implements UrlFilterService {
private static final String CRLF = "\r\n";
@Autowired
private UrlFilterMapper urlFilterMapper;
@Override
public String selectAllPermissions() {
StringBuilder sb = new StringBuilder();
List
for (UrlFilter urlFilter : urls) {
sb.append(urlFilter.getUrl()).append(" == ").append(urlFilter.getPermissions()).append(CRLF);
}
return sb.toString();
}
@Override
public void insertPermissions(UrlFilter urlFilter) {
urlFilterMapper.insertPermissions(urlFilter);
}
}
package com.cn.hnust.service.impl;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.UrlFilenameViewController;
import com.cn.hnust.dao.IUserDao;
import com.cn.hnust.pojo.User;
import com.cn.hnust.service.IUserService;
@Service("userService")
public class UserServiceImpl implements IUserService {
@Resource
private IUserDao userDao;
public User getUserById(Integer userId) {
// TODO Auto-generated method stub
return this.userDao.selectByPrimaryKey(userId);
}
@Override
public User getUserByName(User user) {
if(null == user || null == user.getUserName())
return null;
return userDao.selectByUsername(user.getUserName());
}
}
controller层
package com.cn.hnust.controller;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
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.authz.annotation.RequiresPermissions;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import com.cn.hnust.pojo.User;
import com.cn.hnust.service.IUserService;
import com.cn.hnust.utils.BOSRealm;
import com.cn.hnust.utils.ShiroManager;
@Controller
@RequestMapping("/user")
public class UserController {
@Resource
private IUserService userService;
@Autowired
private ShiroManager shiroManager;
//@RequiresPermissions("sys")
@RequestMapping("/showUser")
public String toIndex(HttpServletRequest request,Model model){
Integer userId = Integer.parseInt(request.getParameter("id"));
User user = this.userService.getUserById(userId);
model.addAttribute("user", user);
return "showUser";
}
@RequestMapping("/login")
public String toLogin(HttpServletRequest request,Model model){
Subject subject = SecurityUtils.getSubject();
String password = request.getParameter("password");
String username = request.getParameter("username");
System.out.println(username+"<----->"+password);
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try{
subject.login(token);
}catch(UnknownAccountException ue){
System.out.println("Exception 用户不存在");
}catch(IncorrectCredentialsException ie){
System.out.println("Exception 密码错误");
}
User user = (User) subject.getPrincipal();
model.addAttribute("user", user);
return "showUser";
}
/**
* 用户登出
*/
@RequestMapping("/logout")
public String logout(HttpServletRequest request){
SecurityUtils.getSubject().logout();
return InternalResourceViewResolver.REDIRECT_URL_PREFIX + "/";
}
/**
* 清除权限
*/
public void clearAuthz(){
RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
BOSRealm realm = (BOSRealm) rsm.getRealms().iterator().next();
realm.clearAuthz();
}
@RequestMapping("/update!initAuth")
public String initAuth(){
shiroManager.reCreateFilterChains();
return InternalResourceViewResolver.REDIRECT_URL_PREFIX + "/";
}
}
package com.cn.hnust.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import com.cn.hnust.pojo.UrlFilter;
import com.cn.hnust.service.impl.UrlFilterServiceImpl;
import com.cn.hnust.utils.ShiroManager;
@Controller
@RequestMapping("/baseUtils")
public class BaseUtilController {
@Autowired
private UrlFilterServiceImpl urlFilterServiceImpl;
@Autowired
private ShiroManager shiroManager;
@RequestMapping("/update!changePermissions")
public String toChangeFilterChain(){
String filterChains = urlFilterServiceImpl.selectAllPermissions();
shiroManager.sqlCreateFilterChains(filterChains);
return InternalResourceViewResolver.REDIRECT_URL_PREFIX + "/";
}
@RequestMapping("/insert!addPermissions")
public String addFilterChain(UrlFilter urlFilter){
urlFilterServiceImpl.insertPermissions(urlFilter);
String filterChains = urlFilterServiceImpl.selectAllPermissions();
System.out.println("重新加载权限:\n"+filterChains);
shiroManager.sqlCreateFilterChains(filterChains);
return "addPermissions";
}
@RequestMapping("/select!showPage")
public String showPage(String pageName){
return pageName;
}
}
utils工具类
package com.cn.hnust.utils;
import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.SecurityUtils;
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.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.cn.hnust.pojo.User;
import com.cn.hnust.service.IUserService;
public class BOSRealm extends AuthorizingRealm{
@Autowired
private IUserService userService;
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principla) {
//获取当前登陆的用户名
SimpleAuthorizationInfo inf = new SimpleAuthorizationInfo();
User principlaUser = (User)super.getAvailablePrincipal(principla);
if(null != principlaUser){
System.out.println("当前登陆的用户--->"+principlaUser.getUserName());
User user = userService.getUserByName(principlaUser);
Set
roles.add(user.getUserName());
Set
perms.add("sys");
perms.add("userAdd");
inf.setRoles(roles);
inf.setStringPermissions(perms);
}
return inf;
}
/**
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) auth;
System.out.println("进行登陆校验的用户="+token.getUsername());
User user = new User();
user.setUserName(token.getUsername());
user = userService.getUserByName(user);
if(null == user)
return null;
return new SimpleAuthenticationInfo(user,(user == null? null :user.getPassword()),this.getClass().getSimpleName());
}
public void clearAuthz(){
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
}
package com.cn.hnust.utils;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import com.cn.hnust.service.impl.UrlFilterServiceImpl;
/**
* 动态加载权限 Service
*/
@Service
public class ShiroManager{
// 注意/r/n前不能有空格
private static final String CRLF = "\r\n";
@Autowired
private ShiroFilterFactoryBean shiroFilterFactoryBean;
public String loadFilterChainDefinitions() {
StringBuffer sb = new StringBuffer();
sb.append(getFixedAuthRule());//固定权限,采用读取配置文件
System.out.println(sb.toString());
return sb.toString();
}
/**
* 从配置文件获取固定权限验证规则串
*/
private String getFixedAuthRule(){
String fileName = "shiro_base_auth.ini";
ClassPathResource cp = new ClassPathResource(fileName);
INI4j ini = null;
try {
ini = new INI4j(cp.getFile());
} catch (IOException e) {
e.printStackTrace();
}
String section = "base_auth";
Set
StringBuffer sb = new StringBuffer();
for (String key : keys) {
String value = ini.get(section, key);
sb.append(key).append(" = ").append(value).append(CRLF);
}
return sb.toString();
}
// 此方法加同步锁
public synchronized void reCreateFilterChains() {
AbstractShiroFilter shiroFilter = null;
try {
shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
} catch (Exception e) {
throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
}
PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
// 清空老的权限控制
manager.getFilterChains().clear();
shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
shiroFilterFactoryBean.setFilterChainDefinitions(loadFilterChainDefinitions());
// 重新构建生成
Map
for (Map.Entry
String url = entry.getKey();
String chainDefinition = entry.getValue().trim().replace(" ", "");
manager.createChain(url, chainDefinition);
}
}
public synchronized void sqlCreateFilterChains(String filterChains) {
AbstractShiroFilter shiroFilter = null;
try {
shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
} catch (Exception e) {
throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
}
PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
// 清空老的权限控制
manager.getFilterChains().clear();
shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
//String filterChains = urlFilterService.selectAllPermissions();
shiroFilterFactoryBean.setFilterChainDefinitions(filterChains);
// 重新构建生成
Map
for (Map.Entry
String url = entry.getKey();
String chainDefinition = entry.getValue().trim().replace(" ", "");
manager.createChain(url, chainDefinition);
}
}
public void setShiroFilterFactoryBean(ShiroFilterFactoryBean shiroFilterFactoryBean) {
this.shiroFilterFactoryBean = shiroFilterFactoryBean;
}
}
package com.cn.hnust.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.core.io.ClassPathResource;
/**
* 有序读取 ini配置文件
*
*/
public class INI4j {
/**
* 用linked hash map 来保持有序的读取
*
*/
final LinkedHashMap
/**
* 当前Section的引用
*/
String currentSection = null;
/**
* 读取
* @param file 文件
* @throws FileNotFoundException
*/
public INI4j(File file) throws FileNotFoundException {
this.init(new BufferedReader(new FileReader(file)));
}
/***
* 重载读取
* @param path 给文件路径
* @throws FileNotFoundException
*/
public INI4j(String path) throws FileNotFoundException {
this.init(new BufferedReader(new FileReader(path)));
}
/***
* 重载读取
* @param source ClassPathResource 文件,如果文件在resource 里,那么直接 new ClassPathResource("file name");
* @throws IOException
*/
public INI4j(ClassPathResource source) throws IOException {
this(source.getFile());
}
void init(BufferedReader bufferedReader){
try {
read(bufferedReader);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("IO Exception:" + e);
}
}
/**
* 读取文件
* @param reader
* @throws IOException
*/
void read(BufferedReader reader) throws IOException {
String line = null;
while((line=reader.readLine())!=null) {
parseLine(line);
}
}
/**
* 转换
* @param line
*/
void parseLine(String line) {
line = line.trim();
// 此部分为注释
if(line.matches("^\\#.*$")) {
return;
}else if (line.matches("^\\[\\S+\\]$")) {
// section
String section = line.replaceFirst("^\\[(\\S+)\\]$","$1");
addSection(section);
}else if (line.matches("^\\S+=.*$")) {
// key ,value
int i = line.indexOf("=");
String key = line.substring(0, i).trim();
String value =line.substring(i + 1).trim();
addKeyValue(currentSection,key,value);
}
}
/**
* 增加新的Key和Value
* @param currentSection
* @param key
* @param value
*/
void addKeyValue(String currentSection,String key, String value) {
if(!coreMap.containsKey(currentSection)) {
return;
}
Map
childMap.put(key, value);
}
/**
* 增加Section
* @param section
*/
void addSection(String section) {
if (!coreMap.containsKey(section)) {
currentSection = section;
LinkedHashMap
coreMap.put(section, childMap);
}
}
/**
* 获取配置文件指定Section和指定子键的值
* @param section
* @param key
* @return
*/
public String get(String section,String key){
if(coreMap.containsKey(section)) {
return get(section).containsKey(key) ? get(section).get(key): null;
}
return null;
}
/**
* 获取配置文件指定Section的子键和值
* @param section
* @return
*/
public Map
return coreMap.containsKey(section) ? coreMap.get(section) : null;
}
/**
* 获取这个配置文件的节点和值
* @return
*/
public LinkedHashMap
return coreMap;
}
}
工程文件位置