shiro与spring Secuity比较:
1 简单灵活
2 科托离spring
3 粒度较粗
spring Secuity与之相反,同时它也是又shiro开发
shiro认证过程:
1 创建secrityManger
2 主体提交认证
3 securityManger认证
4 Realm验证
5 Authenticor认证
代码:
package com.imooc.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
/**认证
* @author fusiping
* 2018年11月23日
*/
public class AuthenticationTest {
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
@Before
public void addUser() {
simpleAccountRealm.addAccount("Mark","123456");
}
@Test
public void testAuthentication() {
//1.构建securityManage环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(simpleAccountRealm);
//设置secutityManager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//2.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("Mark","123456");
subject.login(token);
//结果:isAuthenticated:true
System.out.println("isAuthenticated:"+subject.isAuthenticated());
subject.logout();
//结果:isAuthenticated:false
System.out.println("isAuthenticated:"+subject.isAuthenticated());
}
}
shiro授权:
1 创建SecurityManage
2 主体授权
3 securitymanager授权
4 authorizer授权
5 Realm获取角色权限数据
代码:
package com.imooc.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
/**认证
* @author fusiping
* 2018年11月23日
*/
public class AuthenticationTest {
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
@Before
public void addUser() {
simpleAccountRealm.addAccount("Mark","123456","admin");
}
/**
* 授权
*/
@Test
public void testAuthorizer() {
//1.构建securityManage环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(simpleAccountRealm);
//设置secutityManager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//2.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("Mark","123456");
subject.login(token);
//结果:isAuthenticated:true
System.out.println("isAuthenticated:"+subject.isAuthenticated());
//没有抛出异常,说明验证成功
subject.checkRole("admin");
}
}
shiro自定义Realm
内置Realm:IniRealm,JdbcRealm
package com.imooc.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;public class IniRealmTest {
@Test
public void testIniRealmr() {
//自定义
IniRealm iniRealm = new IniRealm("classpath:user.ini");
//1.构建securityManage环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(iniRealm);
//设置secutityManager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//2.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("Mark","123456");
subject.login(token);
//结果:isAuthenticated:true
System.out.println("isAuthenticated:"+subject.isAuthenticated());
subject.checkRole("user1");
subject.checkPermission("user:update");
}
}
user.ini文件:
[users]
Mark=123456,admin,user1
[roles]
admin=user:delete
user1=user:update
jdbcRealm实例:
package com.imooc.test;
import javax.swing.JScrollBar;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;import com.alibaba.druid.pool.DruidDataSource;
public class JdbcRealmTest {
DruidDataSource dataSource = new DruidDataSource();
{
dataSource.setUrl("jdbc:mysql://localhost:3333/test1");
dataSource.setUsername("test1");
dataSource.setPassword("fsp648734!");
}@Test
public void testIniRealmr() {
JdbcRealm jdbcRealm = new JdbcRealm();
jdbcRealm.setDataSource(dataSource);
//使用jdbcRealm必须设置开关为true,默认为false,否则不能查询权限数据
jdbcRealm.setPermissionsLookupEnabled(true);
//自定义认证查询语句
//jdbcRealm.setAuthenticationQuery("authenticationQuery");
//自定义权限查询语句
//jdbcRealm.setPermissionsQuery("permissionsQuery");
//自定义角色查询语句
//jdbcRealm.setUserRolesQuery("userRolesQuery");
//1.构建securityManage环境
/*
* 默认的查询语句:
protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
*
protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";*/
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(jdbcRealm);
//设置secutityManager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//2.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("fusiping","123456");
subject.login(token);
//结果:isAuthenticated:true
System.out.println("isAuthenticated:"+subject.isAuthenticated());
subject.checkRole("admin");
subject.checkPermission("user:delete");
}
}
默认的sql语句:
对应的数据库表:
CREATE TABLE `roles_permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
`permission` varchar(32) NOT NULL COMMENT '权限',
`role_name` varchar(64) NOT NULL COMMENT '角色',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色-权限';
CREATE TABLE `user_roles` (
`id` int(11) NOT NULL COMMENT '编号',
`username` varchar(255) NOT NULL COMMENT '用户名',
`role_name` varchar(255) NOT NULL COMMENT '角色',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='shiro用户表';
CREATE TABLE `users` (
`id` int(8) NOT NULL AUTO_INCREMENT COMMENT '主键自增',
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(50) NOT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='用户表';
自定义Realm:
package com.imooc.shrio.realm;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
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.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;/**自定义
* @author fusiping
* 2018年11月23日
*/
public class CustomRealm extends AuthorizingRealm{
//模拟数据库查询
Mapmap = new HashMap (16);
{
map.put("fusiping", "123456");
super.setName("customRealm");
}/* 用来做授权
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String) principals.getPrimaryPrincipal();
//从数据库或者从缓存中获取角色数据
Setroles = getRolesByUserName(userName);
//通过用户从从数据库或者从缓存中获取权限数据
Setpermissions = getPermissionsByUserName(userName);
SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
simpleAuthenticationInfo.setStringPermissions(permissions);
simpleAuthenticationInfo.setRoles(roles);
return simpleAuthenticationInfo;
}/**模拟从数据库或缓存中获取权限数据
* @param userName
* @return
*/
private SetgetPermissionsByUserName(String userName) {
Setpermissions = new HashSet ();
permissions.add("user:delete");
permissions.add("user:add");
return permissions;
}/**模拟数据查询
* @param userName
* @return
*/
private SetgetRolesByUserName(String userName) {
Setroles = new HashSet ();
roles.add("admin");
roles.add("user");
return roles;
}/* 用来做认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//1.从主体传过来的认证信息中,获取用户名
String userName = (String) token.getPrincipal();
//2.通过用户名找到数据库中获取凭证
String password = getPasswordByUserName(userName);
if (password == null) {
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("fusiping",password,"customRealm");
return authenticationInfo;
}/**模拟数据库查询凭证
* @param userName
* @return
*/
private String getPasswordByUserName(String userName) {
return map.get(userName);
}
}
测试类CustomRealmTest :
package com.imooc.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;import com.imooc.shrio.realm.CustomRealm;
/**测试
* @author fusiping
* 2018年11月23日
*/
public class CustomRealmTest {@Test
public void testCustomRealm() {
//自定义
CustomRealm customRealm = new CustomRealm();
//1.构建securityManage环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(customRealm);
//设置secutityManager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//2.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("fusiping","123456");
subject.login(token);
//结果:isAuthenticated:true
System.out.println("isAuthenticated:"+subject.isAuthenticated());
subject.checkRole("admin");
subject.checkPermission("user:delete");
}
}
shiro加密:
shiro散列配置:
1 hashedCreadentialsMatcher
2 自定义Realm中使用散列
3 盐的使用
package com.imooc.shrio.realm;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
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.SimpleAuthenticationInfo;
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.apache.shiro.util.ByteSource;/**自定义
* @author fusiping
* 2018年11月23日
*/
public class CustomRealm extends AuthorizingRealm{
//模拟数据库查询
Mapmap = new HashMap (16);
{
map.put("fusiping", "cc2bf701edeca9268997bab3f5b6527d");//123456,Md5加盐“fusiping”,加密后e10adc3949ba59abbe56e057f20f883e
super.setName("customRealm");
}/* 用来做授权
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String) principals.getPrimaryPrincipal();
//从数据库或者从缓存中获取角色数据
Setroles = getRolesByUserName(userName);
//通过用户从从数据库或者从缓存中获取权限数据
Setpermissions = getPermissionsByUserName(userName);
SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
simpleAuthenticationInfo.setStringPermissions(permissions);
simpleAuthenticationInfo.setRoles(roles);
return simpleAuthenticationInfo;
}/**模拟从数据库或缓存中获取权限数据
* @param userName
* @return
*/
private SetgetPermissionsByUserName(String userName) {
Setpermissions = new HashSet ();
permissions.add("user:delete");
permissions.add("user:add");
return permissions;
}/**模拟数据查询
* @param userName
* @return
*/
private SetgetRolesByUserName(String userName) {
Setroles = new HashSet ();
roles.add("admin");
roles.add("user");
return roles;
}/* 用来做认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//1.从主体传过来的认证信息中,获取用户名
String userName = (String) token.getPrincipal();
//2.通过用户名找到数据库中获取凭证
String password = getPasswordByUserName(userName);
if (password == null) {
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("fusiping",password,"customRealm");
//识别加盐
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("fusiping"));
return authenticationInfo;
}/**模拟数据库查询凭证
* @param userName
* @return
*/
private String getPasswordByUserName(String userName) {
return map.get(userName);
}
public static void main(String[] args) {
//加盐:“fusiping”
Md5Hash md5Hash = new Md5Hash("123456","fusiping");
System.out.println(md5Hash.toString());
}
}
测试:
package com.imooc.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;import com.imooc.shrio.realm.CustomRealm;
/**测试
* @author fusiping
* 2018年11月23日
*/
public class CustomRealmTest {@Test
public void testCustomRealm() {
//自定义
CustomRealm customRealm = new CustomRealm();
//1.构建securityManage环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(customRealm);
//加密
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");
//加密次数
matcher.setHashIterations(1);
customRealm.setCredentialsMatcher(matcher);
//设置secutityManager环境
SecurityUtils.setSecurityManager(defaultSecurityManager);
//2.主体提交认证请求
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("fusiping","123456");
subject.login(token);
//结果:isAuthenticated:true
System.out.println("isAuthenticated:"+subject.isAuthenticated());
subject.checkRole("admin");
subject.checkPermission("user:delete");
}
}
shiro+spring整合:
package com.fsp.shiro.realm;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
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.SimpleAuthenticationInfo;
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.apache.shiro.util.ByteSource;
public class CustomRealm extends AuthorizingRealm {
//模拟数据库查询
Map map = new HashMap(16);
{
map.put("fusiping", "cc2bf701edeca9268997bab3f5b6527d");//123456,Md5加盐“fusiping”,加密后e10adc3949ba59abbe56e057f20f883e
super.setName("customRealm");
}
/* 用来做授权
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String) principals.getPrimaryPrincipal();
//从数据库或者从缓存中获取角色数据
Set roles = getRolesByUserName(userName);
//通过用户从从数据库或者从缓存中获取权限数据
Set permissions = getPermissionsByUserName(userName);
SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
simpleAuthenticationInfo.setStringPermissions(permissions);
simpleAuthenticationInfo.setRoles(roles);
return simpleAuthenticationInfo;
}
/**模拟从数据库或缓存中获取权限数据
* @param userName
* @return
*/
private Set getPermissionsByUserName(String userName) {
Set permissions = new HashSet();
permissions.add("user:delete");
permissions.add("user:add");
return permissions;
}
/**模拟数据查询
* @param userName
* @return
*/
private Set getRolesByUserName(String userName) {
Set roles = new HashSet();
roles.add("admin");
roles.add("user");
return roles;
}
/* 用来做认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//1.从主体传过来的认证信息中,获取用户名
String userName = (String) token.getPrincipal();
//2.通过用户名找到数据库中获取凭证
String password = getPasswordByUserName(userName);
if (password == null) {
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("fusiping",password,"customRealm");
//识别加盐
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("fusiping"));
return authenticationInfo;
}
/**模拟数据库查询凭证
* @param userName
* @return
*/
private String getPasswordByUserName(String userName) {
return map.get(userName);
}
}
controller:
package com.fsp.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fsp.controller.req.UserModel;
@Controller
public class UserController {
@RequestMapping(value="/subLogin",method = RequestMethod.POST,produces = "application/json;charset=utf-8")
@ResponseBody
public String subLogin(UserModel userModel) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userModel.getUsername(),userModel.getPassword());
try {
subject.login(token);
} catch (AuthenticationException e) {
return "登陆异常:"+e.getMessage();
}
return "登陆成功";
}
}
userModel:
package com.fsp.controller.req;
import lombok.Getter;
import lombok.Setter;
/**登陆接收model
* @author fusiping
* 2018年11月23日
*/
@Getter
@Setter
public class UserModel {
private String username;
private String password;
}
配置文件:
web.xml:
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
shiroFilter
/*
contextConfigLocation
classpath*:spring/spring.xml
org.springframework.web.context.ContextLoaderListener
org.springframework.web.context.request.RequestContextListener
springServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath*:spring/springmvc.xml
1
springServlet
/
spring.xml:
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"
default-lazy-init="true">
Shiro Configuration
/login.html = anon
/subLogin = anon
/subLogin2 = anon
/* = authc
springmvc.xml:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"
default-lazy-init="true">
login.html:
Insert title here
shiro集成spring从数据库获取数据
spring-dao.xml:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
spring.xml
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"
default-lazy-init="true">
CustomRealm:
package com.fsp.shiro.realm;
import java.util.HashSet;
import java.util.LinkedHashSet;
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.SimpleAuthenticationInfo;
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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import com.fsp.dao.UserDao;
import com.fsp.entity.User;@Component
public class CustomRealm extends AuthorizingRealm {@Autowired
private UserDao userDao;/* 用来做授权
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String) principals.getPrimaryPrincipal();
//从数据库或者从缓存中获取角色数据
Setroles = getRolesByUserName(userName);
//通过用户从从数据库或者从缓存中获取权限数据
Setpermissions = new LinkedHashSet ();
for (String role : roles) {
Setlist = getPermissionsByUserName(role);
permissions.addAll(list);
}
SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
simpleAuthenticationInfo.setStringPermissions(permissions);
simpleAuthenticationInfo.setRoles(roles);
return simpleAuthenticationInfo;
}/**模拟从数据库或缓存中获取权限数据
* @param userName
* @return
*/
private SetgetPermissionsByUserName(String roleName) {
Listlist = userDao.queryPermissionsByUserName(roleName);
Setpermissions = new HashSet (list);
return permissions;
}/**数据查询角色
* @param userName
* @return
*/
private SetgetRolesByUserName(String userName) {
Listlist = userDao.queryRolesByUserName(userName);
Setroles = new HashSet (list);
return roles;
}/* 用来做认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//1.从主体传过来的认证信息中,获取用户名
String userName = (String) token.getPrincipal();
//2.通过用户名找到数据库中获取凭证
String password = getPasswordByUserName(userName);
if (password == null) {
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName,password,"customRealm");
//识别加盐,盐值随意
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userName));
return authenticationInfo;
}/*public static void main(String[] args) {
//数据源+盐
Md5Hash md5 = new Md5Hash("123456","fusiping");
System.out.println(md5.toString());
}*/
/**模拟数据库查询凭证
* @param userName
* @return
*/
private String getPasswordByUserName(String userName) {
User user = userDao.getUserByUserName(userName);
if (user != null) {
return user.getPassword();
}
return null;
}
}
dao:
package com.fsp.dao;
import java.util.List;
import com.fsp.entity.User;
public interface UserDao {
User getUserByUserName(String userName);
List
queryRolesByUserName(String userName); List
queryPermissionsByUserName(String roleName); }
daoImpl:
package com.fsp.dao.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;import com.fsp.dao.UserDao;
import com.fsp.entity.User;@Component
public class UserDaoImpl implements UserDao{@Autowired
private JdbcTemplate jdbcTemplate;
/* 数据库查询密码
* @param userName
* @return
*/
public User getUserByUserName(String userName) {
String sql = "select username, password from users where username = ?";
Listlist = jdbcTemplate.query(sql, new String[] {userName}, new RowMapper () {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
return user;
}
});
if (CollectionUtils.isEmpty(list)) {
return null;
}
return list.get(0);
}/* 数据库查询角色
* @param userName
* @return
*/
public ListqueryRolesByUserName(String userName) {
String sql = "select role_name from user_roles where username = ?";
return jdbcTemplate.query(sql, new String[] {userName}, new RowMapper() {
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getString("role_name");
}
});
}/* 根据角色返回权限数据
* @param roleName
* @return
*/
public ListqueryPermissionsByUserName(String roleName) {
String sql = "select permission from roles_permissions where role_name = ?";
return jdbcTemplate.query(sql, new String[] {roleName}, new RowMapper() {
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getString("permission");
}
});
}}
controller:
package com.fsp.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;import com.fsp.controller.req.UserModel;
@Controller
public class UserController {@RequestMapping(value="/subLogin",method = RequestMethod.POST,produces = "application/json;charset=utf-8")
@ResponseBody
public String subLogin(UserModel userModel) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userModel.getUsername(),userModel.getPassword());
try {
subject.login(token);
} catch (AuthenticationException e) {
return "登陆异常:"+e.getMessage();
}
if (subject.hasRole("admin")) {
subject.checkPermission("user:delete");
return "有admin权限";
}
return "无admin权限";
}
}
通过注解配置权限:
pom.xml添加:
org.aspectj
aspectjweaver
1.8.9
springmvc.xml添加:
controller添加:
/**当前主题必须具备amdin觉得才可以访问
* @return
*/
@RequiresRoles("admin")
@RequestMapping(value="/testRole",method=RequestMethod.GET)
@ResponseBody
public String testRole() {
return "testRole success";
}
/**推荐使用的方法
* @return
*/
@RequiresPermissions("user:delete")
@RequestMapping(value="/testRole1",method=RequestMethod.GET)
@ResponseBody
public String testRole1() {
return "testRole success";
}
shrio内置过滤器:
认证过滤器:anon,authBasic,authc,user,logout
anon:不需要任何认证,直接访问
authBasic:HTTP基本认证
authc:需要认证之后才可以访问
user:需要当前存在用户才能访问
logout;退出、
授权过滤器:perms,roles,ssl,port
perms:需要具备相关权限才可以访问
roles:跟perms差不多,在[]里面满足的相关权限
ssl:https协议
port:[]里面的端口
自定义filter:
package com.fsp.filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;/**自动一授权,如果包含其中一个权限,则执行
* @author fusiping
* 2018年11月27日
*/
public class RoleOrFilter extends AuthorizationFilter {@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception {
Subject subject = getSubject(request, response);
String[] roles = (String[]) mappedValue;
if (roles == null || roles.length == 0 ) {
return true;
}
for (String role : roles) {
if (subject.hasRole(role)) {
return true;
}
}
return false;
}
}
spring.xml:
注入自定义bean
/login.html = anon
/subLogin = anon
/testRole = roles["admin","admin1"] //roles必须包含里面两个角色才能执行
/testRole1 = rolesOr["admin","admin1"] //rolesOr包含其中一个角色就可以执行
/* = authc
controller:
/**roles["admin","admin1"] //roles必须包含里面两个角色才能执行
* @return
*/
@RequestMapping(value="/testRole",method=RequestMethod.GET)
@ResponseBody
public String testRole() {
return "testRole success";
}
/**rolesOr["admin","admin1"] //rolesOr包含其中一个角色就可以执行
* @return
*/
@RequestMapping(value="/testRole1",method=RequestMethod.GET)
@ResponseBody
public String testRole1() {
return "testRole success";
}
shiro会话管理
shiro session管理
sessionmanager,sessionDAO
Redis实现session共享
redis实现Session共享存在的问题
引入maven依赖:
redis.clients
jedis
2.8.0
spring.xml配置文件添加:
RedisSessionDao:
package com.fsp.session;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.SerializationUtils;import com.fsp.util.JedisUtil;
/**
* @author fusiping
* 2018年11月27日
*/
public class RedisSessionDao extends AbstractSessionDAO{
@Autowired
private JedisUtil jedisUtil;
//前缀
private final String SHIRO_SESSION_PREFIX = "fsp-session";
//前缀+key组成的key
private byte[] getKey(String key) {
return (SHIRO_SESSION_PREFIX + key).getBytes();
}
/**保存session
* @param session
*/
private void savaSession(Session session) {
if (session != null && session.getId() != null) {
byte[] key = getKey(session.getId().toString());
byte[] value = SerializationUtils.serialize(session);
jedisUtil.set(key,value);
jedisUtil.expire(key,600);
}
}
/* 创建sessionID
* @param session
* @return
*/
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = generateSessionId(session);
//捆绑session,sessionId
assignSessionId(session, sessionId);
savaSession(session);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
System.out.println("read session");
if (sessionId == null) {
return null;
}
byte[] key = getKey(sessionId.toString());
byte[] value = jedisUtil.get(key);
//反序列化成json对象
return (Session) SerializationUtils.deserialize(value);
}/* 更新session
* @param session
* @throws UnknownSessionException
*/
public void update(Session session) throws UnknownSessionException {
savaSession(session);
}/* 删除session
* @param session
*/
public void delete(Session session) {
if (session == null || session.getId() == null) {
return ;
}
byte[] key = getKey(session.getId().toString());
jedisUtil.del(key);
}/* 获取正在活动的session
* @return
*/
public CollectiongetActiveSessions() {
Setkeys = jedisUtil.keys(SHIRO_SESSION_PREFIX);
Setsessions = new HashSet ();
if (CollectionUtils.isEmpty(keys)) {
return sessions;
}
for (byte[] key : keys) {
Session session = (Session) SerializationUtils.deserialize(jedisUtil.get(key));
sessions.add(session);
}
return sessions;
}
}
添加spring-redis.xml:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
spring.xml引入spring-resdis.xml:
JedisUtil工具类:
package com.fsp.util;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import lombok.val;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;/**redis访问工具包
* @author fusiping
* 2018年11月27日
*/
@Component
public class JedisUtil {@Autowired
private JedisPool jedisPool;
private Jedis getResource() {
return jedisPool.getResource();
}
public byte[] set(byte[] key, byte[] value) {
Jedis jedis = getResource();
try {
jedis.set(key, value);
return value;
} finally {
jedis.close();
}
}public void expire(byte[] key, int i) {
Jedis jedis = getResource();
try {
jedis.expire(key, i);
} finally {
jedis.close();
}
}public byte[] get(byte[] key) {
Jedis jedis = getResource();
try {
return jedis.get(key);
} finally {
jedis.close();
}
}public void del(byte[] key) {
Jedis jedis = getResource();
try {
jedis.del(key);
} finally {
jedis.close();
}
}public Set
keys(String sHIRO_SESSION_PREFIX) {
Jedis jedis = getResource();
try {
//转成二进制
return jedis.keys((sHIRO_SESSION_PREFIX + "*").getBytes());
} finally {
jedis.close();
}
}
}
结果:
注意:必须先启动redis:运行命令:
但是每次请求都会调用多次session,需要优化性能:
所以自定义 SessionManager:
package com.fsp.session;
import java.io.Serializable;
import javax.servlet.ServletRequest;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;/**自定义sessionmanager
* @author fusiping
* 2018年11月27日
*/
public class CustomSessionManager extends DefaultWebSessionManager {
/* 重新retrieveSession
* 先从request中获取,取不到则从redis,取到后在set到request
* @param sessionKey
* @return
* @throws UnknownSessionException
*/
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
// 1先获取sessionId
Serializable sessionId = getSessionId(sessionKey);
ServletRequest request = null;
//先反对是不是WebSessionKey类型
if (sessionKey instanceof WebSessionKey) {
//从sessionkey总获取request
request = ((WebSessionKey) sessionKey).getServletRequest();
}
//如果request != null && sessionId != null
if (request != null && sessionId != null) {
//直接从request中获取session
return (Session) request.getAttribute(sessionId.toString());
}
//那么从retrieveSession中获取
Session session = super.retrieveSession(sessionKey);
if (request != null && sessionId != null) {
request.setAttribute(sessionId.toString(), session);
}
return session;
}}
修改spring.xml:
优化sessionManager
package com.fsp.session;
import java.io.Serializable;
import javax.servlet.ServletRequest;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;/**自定义sessionmanager
* @author fusiping
* 2018年11月27日
*/
public class CustomSessionManager extends DefaultWebSessionManager {
/* 重新retrieveSession
* 先从request中获取,取不到则从redis,取到后在set到request
* @param sessionKey
* @return
* @throws UnknownSessionException
*/
@Override
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
// 1先获取sessionId
Serializable sessionId = getSessionId(sessionKey);
ServletRequest request = null;
//先反对是不是WebSessionKey类型
if (sessionKey instanceof WebSessionKey) {
//从sessionkey总获取request
request = ((WebSessionKey) sessionKey).getServletRequest();
}
//如果request != null && sessionId != null
if (request != null && sessionId != null) {
//直接从request中获取session
Session session = (Session) request.getAttribute(sessionId.toString());
if (session != null ) {
return session;
}
}
//那么从retrieveSession中获取
Session session = super.retrieveSession(sessionKey);
if (request != null && sessionId != null) {
request.setAttribute(sessionId.toString(), session);
}
return session;
}}
优化之后就不用每次都多次调用redis
spring.xml添加:
//shrio session 缓存
RedisCacheManager:
package com.fsp.cache;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired;public class RedisCacheManager implements CacheManager{
@Autowired
private RedisCache redisCache;public
Cache getCache(String arg0) throws CacheException {
return redisCache;
}}
RedisCache:
package com.fsp.cache;
import java.util.Collection;
import java.util.Set;import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.SerializationUtils;import com.fsp.util.JedisUtil;
@Component
public class RedisCacheimplements Cache {
@Autowired
private JedisUtil jedisUtil;
private final String cache_prefix = "fsp-cache";private byte[] getKey(K k) {
if (k instanceof String) {
return (cache_prefix + k).getBytes();
}
return SerializationUtils.serialize(k);
}
public void clear() throws CacheException {
// TODO Auto-generated method stub
}public V get(K k) throws CacheException {
System.out.println("从reids中获取权限数据");
byte[] value = jedisUtil.get(getKey(k));
if (value != null ) {
return (V) SerializationUtils.deserialize(value);
}
return null;
}public Set
keys() {
return null;
}public V put(K arg0, V arg1) throws CacheException {
byte[] key = getKey(arg0);
byte[] value = SerializationUtils.serialize(arg1);
jedisUtil.set(key, value);
jedisUtil.expire(key, 600);
return arg1;
}/* 删除
* @param arg0
* @return
* @throws CacheException
*/
public V remove(K arg0) throws CacheException {
byte[] key = getKey(arg0);
byte[] value = jedisUtil.get(key);
jedisUtil.del(key);
if (value != null) {
return (V) SerializationUtils.deserialize(value);
}
return null;
}public int size() {
// TODO Auto-generated method stub
return 0;
}public Collection
values() {
// TODO Auto-generated method stub
return null;
}}
记住我功能:
spring.xml:
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"
default-lazy-init="true">
/login.html = anon
/subLogin = anon
/testRole = roles["admin","admin1"]
/testRole1 = rolesOr["admin","admin1"]
/* = authc
loginController:
@RequestMapping(value="/subLogin",method = RequestMethod.POST,produces = "application/json;charset=utf-8")
@ResponseBody
public String subLogin(UserModel userModel) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userModel.getUsername(),userModel.getPassword());
try {
token.setRememberMe(userModel.isRememberMe());
subject.login(token);
} catch (AuthenticationException e) {
return "登陆异常:"+e.getMessage();
}
if (subject.hasRole("admin")) {
subject.checkPermission("user:delete");
return "有admin权限";
}
return "无admin权限";
}
login.xml:
Insert title here