近期由于使用shiro作为安全框架作为项目中要使用的权限管理,在此分享一下shiro于spring和springmvc集成的demo
1.首先添加web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <display-name>shiro测试</display-name> <!-- shiroFilter --> <filter> <filter-name>shiroFilter</filter-name> <!-- 代理类,自动到spring配置文件中找shiro配置文件 --> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 加载spring配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- springmvc配置文件加载 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 使用spring解决乱码问题 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> </web-app>
2.SpringMVC配置文件springmvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <!-- <bean id="myController" name="/control.action" class="com.cai.controller.MyController"></bean> --> <!-- 支持注解驱动 --> <mvc:annotation-driven/> <!-- shiro中注解起作用必须配置在springmvc配置文件中,配置在其他地方无效 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <!-- 配置异常跳转页面,此处异常页面是使用shiro注解时没有权限访问的跳转页面,不配置则会报500错误 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.UnauthorizedException"> <!-- 没有权限时跳转的页面 --> /unauthorized </prop> <prop key="org.apache.shiro.authz.UnauthenticatedException"> <!-- 认证错误时跳转的页面 --> /unauthenticated </prop> </props> </property> </bean> <!-- 组件扫描的包 --> <context:component-scan base-package="com.cai.controller"/> <!-- 静态资源目录 --> <mvc:resources mapping="/js/**" location="/js/" /> <mvc:resources mapping="/images/**" location="/images/" /> <mvc:resources mapping="/css/**" location="/css/" /> <mvc:resources mapping="/common/**" location="/common/" /> <!-- 配置视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 通过setter方法注入前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 通过setter方法注入后缀 --> <property name="suffix" value=".jsp"></property> </bean> </beans>
3.Spring配置文件beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <!-- 组件扫描 --> <context:component-scan base-package="com.cai.*"/> <!--数据库配置:配置jdbc.properties --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 3、配置dataSource数据源c3p0 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClassName}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- <property name="maxPoolSize" value="${c3p0.pool.maxPoolSize}"/> <property name="minPoolSize" value="${c3p0.pool.minPoolSize}"/> <property name="initialPoolSize" value="${c3p0.pool.initialPoolSize}"/> <property name="acquireIncrement" value="${c3p0.pool.acquireIncrement}"/> --> </bean> <!-- 数据源使用Spring自带的jdbctemplate --> <bean id="jdbcTemplate" name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="userDao" name="userDao" class="com.cai.dao.UserDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="baseDao" name="baseDao" class="com.cai.dao.BaseDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <!-- <bean id="baseDao" name="baseDao" class="com.cai.dao.BaseDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> --> <!-- 事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 导入shiro配置文件 --> <import resource="shiro.xml"/> </beans>
4.jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/shiro?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8 jdbc.username=root jdbc.password=123456
5.缓存ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true"> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
6.java代码
MD5加密
public class MD5Utils {
/**
* 使用md5的算法进行加密
* 此处使用的是shiro自带的md5加密方法
*/
public static String md5(String password) {
Md5Hash md5 = new Md5Hash(password);
return md5.toString();
}
}
实体类javabean
public class User {
private int id;
private String username;//用户名
private String password;//用户密码
private String realname;//真实名字
private String email;//emai地址
private String phone;//电话号码
private List<Role> roles = new ArrayList<Role>();
/**
* @return the roles
*/
public List<Role> getRoles() {
return roles;
}
/**
* @param roles the roles to set
*/
public void setRoles(List<Role> roles) {
this.roles = roles;
}
....都是get、set方法
}
public class Role {
private int id;
private String rolename;//角色名
private String roletype;//角色类型
List<Permission> perms = new ArrayList<Permission>();
/**
* @return the perms
*/
public List<Permission> getPerms() {
return perms;
}
/**
* @param perms the perms to set
*/
public void setPerms(List<Permission> perms) {
this.perms = perms;
}
//...get set方法
}
public class Permission {
private int id;
private String permname;//权限名称
private String operation;//权限操作
private String description;//权限描述
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
//...get set方法
}
Dao层
@Repository
public class BaseDao extends JdbcDaoSupport {
/**
* 条件查询
* @param sql
* @param id
* @return
*/
public Map<String, Object> querySingle(String sql,Object... args) {
return this.getJdbcTemplate().queryForMap(sql, args);
}
/**
* 根据sql查询
* @param sql
* @return
*/
public Map<String, Object> queryAll(String sql) {
return this.getJdbcTemplate().queryForMap(sql);
}
/**
* 查询集合
* @param sql
* @return
*/
public List<Map<String, Object>> queryList(String sql) {
return this.getJdbcTemplate().queryForList(sql);
}
/**
* 条件查询集合
* @param sql
* @param args
* @return
*/
public List<Map<String, Object>> queryList(String sql, Object... args) {
return this.getJdbcTemplate().queryForList(sql, args);
}
/**
* 更新记录条数
* @param sql
* @return
*/
public int update(String sql) {
return this.getJdbcTemplate().update(sql);
}
/**
* 按条件更新
* @param sql
* @param args
* @return
*/
public int update(String sql, Object... args) {
return this.getJdbcTemplate().update(sql, args);
}
/**
* 添加记录
* @param sql
*/
public void add(String sql) {
this.getJdbcTemplate().execute(sql);
}
/**
* 删除记录
* @param sql
*/
public void delete(String sql) {
this.getJdbcTemplate().execute(sql);
}
}
@Repository
public class UserDao extends JdbcDaoSupport {
/**
* 登录查询
* @param sql
* @param username
* @param password
* @return
*/
public Map<String, Object> loginQuery(String sql, String username, String password) {
return this.getJdbcTemplate().queryForMap(sql, username, password);
}
/**
* 登录查询
* @param sql
* @param username
* @param password
* @return
*/
public Map<String, Object> loginQuery(String sql, String username) {
return this.getJdbcTemplate().queryForMap(sql, username);
}
}
Service 层
@Service
public class UserService {
@Autowired
UserDao userDao;
@Autowired
BaseDao baseDao;
public Map<String, Object> queryLogin(String username, String password) {
String sql = "select username, password from user where username=? and password=?";
return userDao.loginQuery(sql, username, password);
}
public User queryLogin(String username) {
String sql = "select * from user where username=?";
Map<String, Object> query = userDao.loginQuery(sql,username);
User user = new User();
if(query != null && query.size() > 0) {
if(query.get("id") != null) {
user.setId(Integer.parseInt(query.get("id").toString()));
}
if(query.get("username") != null) {
user.setUsername(query.get("username").toString());
}
if(query.get("password") != null) {
user.setPassword(query.get("password").toString());
}
if(query.get("realname") != null) {
user.setRealname(query.get("realname").toString());
}
if(query.get("email") != null) {
user.setEmail(query.get("email").toString());
}
if(query.get("phone") != null) {
user.setPhone(query.get("phone").toString());
}
}
return user;
}
}
@Service
public class ShiroService {
@Autowired
BaseDao baseDao;
/**
* 根据角色id获取对应的权限id
* @param roleid
* @return
*/
public List<Map<String, Object>> getPermissions(int roleid) {
String sql = "select * from role_permission where role_id=?";
return baseDao.queryList(sql, roleid);
}
/**
* 通过用户id获取角色
* @param userid
* @return
*/
public List<Map<String, Object>> getRoles(int userid){
String sql = "select * from role where id in (select role_id from user_role where user_id=?)";
return baseDao.queryList(sql, userid);
}
/**
* 添加权限id
* @param permid
*/
/*public void addPerm(int permid) {
String sql = "insert into role_permission";
}*/
/**
* 查询所有的权限
* @param role
* @return
*/
public List<Map<String, Object>> getPermissions(Role role) {
String sql = "select * from permission where id in (SELECT permission_id from role_permission WHERE role_id=?)";
return baseDao.queryList(sql, role.getId());
}
/**
* 查询所有的角色
* @param user
* @return
*/
public List<Map<String, Object>> getRoles(User user) {
String sql = "select * from role where id in (select role_id from user_role where user_id=?)";
return baseDao.queryList(sql, user.getId());
}
}
Shiro核心
@Service
public class MyRealm extends AuthorizingRealm{
@Autowired
ShiroService shiroService;
@Autowired
UserService userService;
/* (non-Javadoc)
* @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//获取当前登录用户名
//String account = (String) principals.fromRealm(getName()).iterator().next();
// String account = (String)getAvailablePrincipal(principals);
Subject subject = SecurityUtils.getSubject();
String account = (String) subject.getPrincipal();
User user = userService.queryLogin(account);
List<Map<String,Object>> roleList = shiroService.getRoles(user);
for (Map<String, Object> roles : roleList) {
authorizationInfo.addRole(roles.get("roletype").toString());
Role role = new Role();
role.setId(Integer.parseInt((roles.get("id").toString())));
List<Map<String, Object>> permissionsList = shiroService.getPermissions(role);
for (Map<String, Object> perms : permissionsList) {
authorizationInfo.addStringPermission(perms.get("operation").toString());
}
}
return authorizationInfo;
}
/* (non-Javadoc)
* @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
//根据用户名查询数据库
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;//封装认证对象
User user = userService.queryLogin(usernamePasswordToken.getUsername());
if(user == null) {
//用户不存在
return null;
}
//返回密码
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());//getName获取当前的realm
//比较密码
return authenticationInfo;
}
}
Controller
@Controller
public class UserController {
@Autowired
UserService userService;
@RequestMapping(value="/login")
public String login (HttpServletRequest request) {
//非shiro登录
/*String username = request.getParameter("username");
String password = request.getParameter("password");
Map<String, Object> queryLogin = userService.queryLogin(username, MD5Utils.md5(password));
if(queryLogin != null) {
return "success";
} else {
return "fail";
}*/
return "login";
}
@RequestMapping(value="/checklogin")
@ResponseBody
public String checkLogin(HttpServletRequest request) {
String username = request.getParameter("username");
String password = request.getParameter("password");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, MD5Utils.md5(password));
token.setRememberMe(true);
try {
subject.login(token);
request.getSession().setAttribute("account", username);
} catch (AuthenticationException e) {
//e.printStackTrace();
return "/login";
}
return "/first";
}
@RequestMapping(value="/manage/first")
public String main(HttpServletRequest request) {
//String
return "/manage/first";
}
@RequestMapping(value="/operation/add")
public String add(HttpServletRequest request) {
return "/operation/add";
}
//@RequiresRoles("administrator")
@RequestMapping(value="/operation/delete")
public String delete(HttpServletRequest request) {
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole("administrator")) {
return "/operation/delete";
} else {
return "/manage/unauthorized";
}
}
@RequestMapping(value="/operation/update")
@RequiresRoles("header")
public String update(HttpServletRequest request) {
return "/operation/update";
}
@RequestMapping(value="/operation/query")
public String query(HttpServletRequest request) {
return "/operation/query";
}
@RequestMapping(value="/search/search")
public String search(HttpServletRequest request) {
return "/search/search";
}
@RequestMapping(value="/manage/unauthorized")
public String error(HttpServletRequest request) {
return "/manage/unauthorized";
}
@RequestMapping(value="/logout", method=RequestMethod.GET)
public String logout() {
Subject subject = SecurityUtils.getSubject();
if(subject.isAuthenticated()) {
subject.logout();
//return "login";
}
return "redirect:login";
}
}
jsp页面在下面的文件中,下载后创建数据库执行sql,直接导入项目就行 了