首先先贴一下代码结构
1、SQL
drop table if exists sys_users;
drop table if exists sys_roles;
drop table if exists sys_permissions;
drop table if exists sys_users_roles;
drop table if exists sys_roles_permissions;
create table sys_users (
id bigint auto_increment,
username varchar(100),
password varchar(100),
salt varchar(100),
locked bool default false,
constraint pk_sys_users primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_sys_users_username on sys_users(username);
create table sys_roles (
id bigint auto_increment,
role varchar(100),
description varchar(100),
available bool default false,
constraint pk_sys_roles primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_sys_roles_role on sys_roles(role);
create table sys_permissions (
id bigint auto_increment,
permission varchar(100),
description varchar(100),
available bool default false,
constraint pk_sys_permissions primary key(id)
) charset=utf8 ENGINE=InnoDB;
create unique index idx_sys_permissions_permission on sys_permissions(permission);
create table sys_users_roles (
user_id bigint,
role_id bigint,
constraint pk_sys_users_roles primary key(user_id, role_id)
) charset=utf8 ENGINE=InnoDB;
create table sys_roles_permissions (
role_id bigint,
permission_id bigint,
constraint pk_sys_roles_permissions primary key(role_id, permission_id)
) charset=utf8 ENGINE=InnoDB;
2、pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.java.shiro</groupId>
<artifactId>Shiro4</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Shiro4</name>
<description>Shiro4</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>0.2.23</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
</dependencies>
</project>
3、实体类
package com.java.shiro.entity;
import java.io.Serializable;
public class Permission implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String permission; //权限标识 程序中判断使用,如"user:create"
private String description; //权限描述,UI界面显示使用
private Boolean available = Boolean.FALSE; //是否可用,如果不可用将不会添加给用户
public Permission() {
}
public Permission(String permission, String description, Boolean available) {
this.permission = permission;
this.description = description;
this.available = available;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Boolean getAvailable() {
return available;
}
public void setAvailable(Boolean available) {
this.available = available;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Permission role = (Permission) o;
if (id != null ? !id.equals(role.id) : role.id != null) return false;
return true;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", permission='" + permission + '\'' +
", description='" + description + '\'' +
", available=" + available +
'}';
}
}
package com.java.shiro.entity;
import java.io.Serializable;
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String role; //角色标识 程序中判断使用,如"admin"
private String description; //角色描述,UI界面显示使用
private Boolean available = Boolean.FALSE; //是否可用,如果不可用将不会添加给用户
public Role() {
}
public Role(String role, String description, Boolean available) {
this.role = role;
this.description = description;
this.available = available;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Boolean getAvailable() {
return available;
}
public void setAvailable(Boolean available) {
this.available = available;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Role role = (Role) o;
if (id != null ? !id.equals(role.id) : role.id != null) return false;
return true;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", role='" + role + '\'' +
", description='" + description + '\'' +
", available=" + available +
'}';
}
}
package com.java.shiro.entity;
import java.io.Serializable;
public class RolePermssion implements Serializable {
private static final long serialVersionUID = 1L;
private Long roleId;
private Long permissionId;
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
public Long getPermissionId() {
return permissionId;
}
public void setPermissionId(Long permissionId) {
this.permissionId = permissionId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RolePermssion that = (RolePermssion) o;
if (permissionId != null ? !permissionId.equals(that.permissionId) : that.permissionId != null) return false;
if (roleId != null ? !roleId.equals(that.roleId) : that.roleId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = roleId != null ? roleId.hashCode() : 0;
result = 31 * result + (permissionId != null ? permissionId.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "RolePermssion{" +
"roleId=" + roleId +
", permissionId=" + permissionId +
'}';
}
}
package com.java.shiro.entity;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;//编号
private String username;//用户名
private String password;//密码
private String salt;//盐
private Boolean locked = Boolean.FALSE;//是否锁定
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long 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 String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getCredentialsSalt() {
return username + salt;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (id != null ? !id.equals(user.id) : user.id != null) return false;
return true;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", salt='" + salt + '\'' +
", locked=" + locked +
'}';
}
}
package com.java.shiro.entity;
import java.io.Serializable;
public class UserRole implements Serializable {
private static final long serialVersionUID = 1L;
private Long userId;
private Long roleId;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserRole userRole = (UserRole) o;
if (roleId != null ? !roleId.equals(userRole.roleId) : userRole.roleId != null) return false;
if (userId != null ? !userId.equals(userRole.userId) : userRole.userId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = userId != null ? userId.hashCode() : 0;
result = 31 * result + (roleId != null ? roleId.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "UserRole{" +
"userId=" + userId +
", roleId=" + roleId +
'}';
}
}
4、Dao及实现类
package com.java.shiro.dao;
import com.java.shiro.entity.Permission;
public interface PermissionDao {
public Permission createPermission(Permission permission);
public void deletePermission(Long permissionId);
}
package com.java.shiro.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import com.java.shiro.dao.PermissionDao;
import com.java.shiro.entity.Permission;
import com.java.shiro.util.JdbcTemplateUtils;
public class PermissionDaoImpl implements PermissionDao {
private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();
@Override
public Permission createPermission(final Permission permission) {
final String sql = "insert into sys_permissions(permission, description, available) values(?,?,?)";
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
PreparedStatement psst = con.prepareStatement(sql,new String[]{"id"});
psst.setString(1,permission.getPermission());
psst.setString(2,permission.getDescription());
psst.setBoolean(3,permission.getAvailable());
return psst;
}
}, keyHolder);
permission.setId(keyHolder.getKey().longValue());
return permission;
}
@Override
public void deletePermission(Long permissionId) {
//首先把与permission关联的相关表的数据删掉
String sql = "delete from sys_roles_permissions where permission_id=?";
jdbcTemplate.update(sql, permissionId);
sql = "delete from sys_permissions where id=?";
jdbcTemplate.update(sql, permissionId);
}
}
package com.java.shiro.dao;
import com.java.shiro.entity.Role;
public interface RoleDao {
public Role createRole(Role role);
public void deleteRole(Long roleId);
public void correlationPermissions(Long roleId, Long... permissionIds);
public void uncorrelationPermissions(Long roleId, Long... permissionIds);
}
package com.java.shiro.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import com.java.shiro.dao.RoleDao;
import com.java.shiro.entity.Role;
import com.java.shiro.util.JdbcTemplateUtils;
public class RoleDaoImpl implements RoleDao {
private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();
/**
* 新建角色
*/
@Override
public Role createRole(final Role role) {
final String sql = "insert into sys_roles(role, description, available) values(?,?,?)";
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
PreparedStatement psst = con.prepareStatement(sql, new String[]{"id"});
psst.setString(1,role.getRole());
psst.setString(2,role.getDescription());
psst.setBoolean(3,role.getAvailable());
return psst;
}
}, keyHolder);
role.setId(keyHolder.getKey().longValue());
return role;
}
/**
* 删除角色
*/
@Override
public void deleteRole(Long roleId) {
//首先把和role关联的相关表数据删掉
String sql = "delete from sys_users_roles where role_id=?";
jdbcTemplate.update(sql, roleId);
sql = "delete from sys_roles where id=?";
jdbcTemplate.update(sql, roleId);
}
/**
* 添加角色-权限之间关系
*/
@Override
public void correlationPermissions(Long roleId, Long... permissionIds) {
if (permissionIds == null || permissionIds.length == 0) {
return;
}
String sql = "insert into sys_roles_permissions(role_id, permission_id) values(?,?)";
for (Long permissionId : permissionIds) {
if (!exists(roleId, permissionId)) {
jdbcTemplate.update(sql, roleId,permissionId);
}
}
}
/**
* 移除角色-权限之间关系
*/
@Override
public void uncorrelationPermissions(Long roleId, Long... permissionIds) {
if (permissionIds == null || permissionIds.length == 0) {
return;
}
String sql = "delete from sys_roles_permissions where role_id=? and permission_id=?";
for (Long permissionId : permissionIds) {
if (!exists(roleId, permissionId)) {
jdbcTemplate.update(sql, roleId,permissionId);
}
}
}
private boolean exists(Long roleId, Long permissionId) {
String sql = "select count(1) from sys_roles_permissions where role_id=? and permission_id=?";
return jdbcTemplate.queryForObject(sql, Integer.class, roleId, permissionId) != 0;
}
}
package com.java.shiro.dao;
import java.util.Set;
import com.java.shiro.entity.User;
public interface UserDao {
public User createUser(User user);
public void updateUser(User user);
public void deleteUser(Long userId);
public void correlationRoles(Long userId, Long... roleIds);
public void uncorrelationRoles(Long userId, Long... roleIds);
User findOne(Long userId);
User findByUsername(String username);
Set<String> findRoles(String username);
Set<String> findPermissions(String username);
}
package com.java.shiro.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import com.java.shiro.dao.UserDao;
import com.java.shiro.entity.User;
import com.java.shiro.util.JdbcTemplateUtils;
public class UserDaoImpl implements UserDao {
private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();
/**
* 新增用户
*/
@Override
public User createUser(final User user) {
final String sql = "insert into sys_users(username, password, salt, locked) values(?,?,?, ?)";
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException {
PreparedStatement psst = con.prepareStatement(sql, new String[]{"id"});
psst.setString(1,user.getUsername());
psst.setString(2,user.getPassword());
psst.setString(3,user.getSalt());
psst.setBoolean(4,user.getLocked());
return psst;
}
}, keyHolder);
user.setId(keyHolder.getKey().longValue());
return user;
}
/**
* 更新用户
*/
@Override
public void updateUser(User user) {
String sql = "update sys_users set username=?, password=?, salt=?, locked=? where id=?";
jdbcTemplate.update(sql, user.getUsername(),user.getPassword(),user.getSalt(),user.getLocked(),user.getId());
}
/**
* 删除用户
*/
@Override
public void deleteUser(Long userId) {
String sql = "delete from sys_users where id=?";
jdbcTemplate.update(sql, userId);
}
/**
* 添加用户-角色关系
*/
@Override
public void correlationRoles(Long userId, Long... roleIds) {
if (roleIds == null || roleIds.length == 0) {
return;
}
String sql = "insert into sys_users_roles(user_id, role_id) values(?,?)";
for (Long roleId : roleIds) {
if (!exists(userId, roleId)) {
jdbcTemplate.update(sql, userId,roleId);
}
}
}
/**
* 移除用户-角色关系
*/
@Override
public void uncorrelationRoles(Long userId, Long... roleIds) {
if (roleIds == null || roleIds.length == 0) {
return;
}
String sql = "delete from sys_users_roles where user_id=? and role_id=?";
for (Long roleId : roleIds) {
if (!exists(userId, roleId)) {
jdbcTemplate.update(sql, userId,roleId);
}
}
}
/**
* 根据 userId 获取用户
*/
@Override
public User findOne(Long userId) {
String sql = "select id, username, password, salt, locked from sys_users where id=?";
List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(User.class), userId);
if(userList.size() == 0) {
return null;
}
return userList.get(0);
}
/**
* 根据 username 获取用户
*/
@Override
public User findByUsername(String username) {
String sql = "select id, username, password, salt, locked from sys_users where username=?";
List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(User.class), username);
if(userList.size() == 0) {
return null;
}
return userList.get(0);
}
/**
* 根据 username 获取用户角色
*/
@Override
public Set<String> findRoles(String username) {
String sql = "select role from sys_users u, sys_roles r,sys_users_roles ur where u.username=? and u.id=ur.user_id and r.id=ur.role_id";
return new HashSet(jdbcTemplate.queryForList(sql, String.class, username));
}
/**
* 根据 username 获取用户权限
*/
@Override
public Set<String> findPermissions(String username) {
//TODO 此处可以优化,比如查询到role后,一起获取roleId,然后直接根据roleId获取即可
String sql = "select permission from sys_users u, sys_roles r, sys_permissions p, sys_users_roles ur, sys_roles_permissions rp where u.username=? and u.id=ur.user_id and r.id=ur.role_id and r.id=rp.role_id and p.id=rp.permission_id";
return new HashSet(jdbcTemplate.queryForList(sql, String.class, username));
}
private boolean exists(Long userId, Long roleId) {
String sql = "select count(1) from sys_users_roles where user_id=? and role_id=?";
return jdbcTemplate.queryForObject(sql, Integer.class, userId, roleId) != 0;
}
}
5、service及实现类
package com.java.shiro.service;
import com.java.shiro.entity.Permission;
public interface PermissionService {
public Permission createPermission(Permission permission);
public void deletePermission(Long permissionId);
}
package com.java.shiro.service.impl;
import com.java.shiro.dao.PermissionDao;
import com.java.shiro.dao.impl.PermissionDaoImpl;
import com.java.shiro.entity.Permission;
import com.java.shiro.service.PermissionService;
public class PermissionServiceImpl implements PermissionService{
private PermissionDao permissionDao = new PermissionDaoImpl();
@Override
public Permission createPermission(Permission permission) {
return permissionDao.createPermission(permission);
}
@Override
public void deletePermission(Long permissionId) {
permissionDao.deletePermission(permissionId);
}
}
package com.java.shiro.service;
import com.java.shiro.entity.Role;
public interface RoleService {
public Role createRole(Role role);
public void deleteRole(Long roleId);
/**
* 添加角色-权限之间关系
* @param roleId
* @param permissionIds
*/
public void correlationPermissions(Long roleId, Long... permissionIds);
/**
* 移除角色-权限之间关系
* @param roleId
* @param permissionIds
*/
public void uncorrelationPermissions(Long roleId, Long... permissionIds);
}
package com.java.shiro.service.impl;
import com.java.shiro.dao.RoleDao;
import com.java.shiro.dao.impl.RoleDaoImpl;
import com.java.shiro.entity.Role;
import com.java.shiro.service.RoleService;
public class RoleServiceImpl implements RoleService{
private RoleDao roleDao = new RoleDaoImpl();
@Override
public Role createRole(Role role) {
return roleDao.createRole(role);
}
@Override
public void deleteRole(Long roleId) {
roleDao.deleteRole(roleId);
}
/**
* 添加角色-权限之间关系
* @param roleId
* @param permissionIds
*/
@Override
public void correlationPermissions(Long roleId, Long... permissionIds) {
roleDao.correlationPermissions(roleId, permissionIds);
}
/**
* 移除角色-权限之间关系
* @param roleId
* @param permissionIds
*/
@Override
public void uncorrelationPermissions(Long roleId, Long... permissionIds) {
roleDao.uncorrelationPermissions(roleId, permissionIds);
}
}
package com.java.shiro.service;
import java.util.Set;
import com.java.shiro.entity.User;
public interface UserService {
/**
* 创建用户
* @param user
*/
public User createUser(User user);
/**
* 修改密码
* @param userId
* @param newPassword
*/
public void changePassword(Long userId, String newPassword);
/**
* 添加用户-角色关系
* @param userId
* @param roleIds
*/
public void correlationRoles(Long userId, Long... roleIds);
/**
* 移除用户-角色关系
* @param userId
* @param roleIds
*/
public void uncorrelationRoles(Long userId, Long... roleIds);
/**
* 根据用户名查找用户
* @param username
* @return
*/
public User findByUsername(String username);
/**
* 根据用户名查找其角色
* @param username
* @return
*/
public Set<String> findRoles(String username);
/**
* 根据用户名查找其权限
* @param username
* @return
*/
public Set<String> findPermissions(String username);
}
package com.java.shiro.service.impl;
import java.util.Set;
import com.java.shiro.dao.UserDao;
import com.java.shiro.dao.impl.UserDaoImpl;
import com.java.shiro.entity.User;
import com.java.shiro.service.UserService;
import com.java.shiro.util.PasswordHelper;
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoImpl();
private PasswordHelper passwordHelper = new PasswordHelper();
/**
* 创建用户
* @param user
*/
public User createUser(User user) {
//加密密码
passwordHelper.encryptPassword(user);
return userDao.createUser(user);
}
/**
* 修改密码
* @param userId
* @param newPassword
*/
public void changePassword(Long userId, String newPassword) {
User user =userDao.findOne(userId);
user.setPassword(newPassword);
passwordHelper.encryptPassword(user);
userDao.updateUser(user);
}
/**
* 添加用户-角色关系
* @param userId
* @param roleIds
*/
public void correlationRoles(Long userId, Long... roleIds) {
userDao.correlationRoles(userId, roleIds);
}
/**
* 移除用户-角色关系
* @param userId
* @param roleIds
*/
public void uncorrelationRoles(Long userId, Long... roleIds) {
userDao.uncorrelationRoles(userId, roleIds);
}
/**
* 根据用户名查找用户
* @param username
* @return
*/
public User findByUsername(String username) {
return userDao.findByUsername(username);
}
/**
* 根据用户名查找其角色
* @param username
* @return
*/
public Set<String> findRoles(String username) {
return userDao.findRoles(username);
}
/**
* 根据用户名查找其权限
* @param username
* @return
*/
public Set<String> findPermissions(String username) {
return userDao.findPermissions(username);
}
}
6、公共类
package com.java.shiro.util;
import org.springframework.jdbc.core.JdbcTemplate;
import com.alibaba.druid.pool.DruidDataSource;
public class JdbcTemplateUtils {
private static JdbcTemplate jdbcTemplate;
private static JdbcTemplate createJdbcTemplate(){
DruidDataSource pool = new DruidDataSource();
pool.setDriverClassName("com.mysql.jdbc.Driver");
pool.setUrl("jdbc:mysql://localhost:3306/db_shiro");
pool.setUsername("root");
pool.setPassword("root");
return new JdbcTemplate(pool);
}
public static JdbcTemplate jdbcTemplate(){
if (jdbcTemplate == null) {
jdbcTemplate = createJdbcTemplate();
}
return jdbcTemplate;
}
}
package com.java.shiro.util;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import com.java.shiro.entity.User;
public class PasswordHelper {
private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
private String algorithmName = "md5";
private final int hashIterations = 2;
public void encryptPassword(User user) {
user.setSalt(randomNumberGenerator.nextBytes().toHex());
String newPassword = new SimpleHash(algorithmName,user.getPassword(),ByteSource.Util.bytes(user.getCredentialsSalt()),hashIterations).toHex();
user.setPassword(newPassword);
}
}
7、自定义 realm
package com.java.shiro.realm;
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.realm.Realm;
public class MyRealm1 implements Realm{
@Override
public String getName() {
return "a"; //realm name 为 “a”
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
return new SimpleAuthenticationInfo(
"zhang", //身份 字符串类型
"123", //凭据
getName() //Realm Name
);
}
}
package com.java.shiro.realm;
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.realm.Realm;
public class MyRealm2 implements Realm{
@Override
public String getName() {
return "b"; //realm name 为 “b”
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
return new SimpleAuthenticationInfo(
"zhang", //身份 字符串类型
"123", //凭据
getName() //Realm Name
);
}
}
package com.java.shiro.realm;
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.realm.Realm;
import com.java.shiro.entity.User;
public class MyRealm3 implements Realm{
@Override
public String getName() {
return "c"; //realm name 为 “c”
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
User user = new User("zhang", "123");
return new SimpleAuthenticationInfo(
user, //身份 User类型
"123", //凭据
getName() //Realm Name
);
}
}
package com.java.shiro.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UnknownAccountException;
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 com.java.shiro.entity.User;
import com.java.shiro.service.UserService;
import com.java.shiro.service.impl.UserServiceImpl;
public class UserRealm extends AuthorizingRealm {
private UserService userService = new UserServiceImpl();
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(userService.findRoles(username));
authorizationInfo.setStringPermissions(userService.findPermissions(username));
return authorizationInfo;
}
/**
* 验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username =(String)token.getPrincipal();
User user = userService.findByUsername(username);
if (user == null) {
throw new UnknownAccountException();//没有找到账号
}
if (Boolean.TRUE.equals(user.getLocked())) {
throw new LockedAccountException();//账号已锁定
}
AuthenticationInfo authenticationInfo = new SimpleAccount(
user.getUsername(),//用户名
user.getPassword(),//密码
ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
getName());
return authenticationInfo;
}
}
8、资质认证
package com.java.shiro.credentials;
import java.util.concurrent.atomic.AtomicInteger;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher{
private Ehcache passwordRetryCache;
public RetryLimitHashedCredentialsMatcher() {
CacheManager cacheManager = CacheManager.newInstance(CacheManager.class.getClassLoader().getResource("ehcache.xml"));
passwordRetryCache = cacheManager.getCache("passwordRetryCache");
}
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
String username = (String)token.getPrincipal();
//retry count + 1
Element element = passwordRetryCache.get(username);
if(element == null) {
element = new Element(username , new AtomicInteger(0));
passwordRetryCache.put(element);
}
AtomicInteger retryCount = (AtomicInteger)element.getObjectValue();
if(retryCount.incrementAndGet() > 5) {
//if retry count > 5 throw
throw new ExcessiveAttemptsException();
}
boolean matches = super.doCredentialsMatch(token, info);
if(matches) {
//clear retry count
passwordRetryCache.remove(username);
}
return matches;
}
}
9、配置文件
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="es">
<diskStore path="java.io.tmpdir"/>
<!-- 登录记录缓存 锁定10分钟 -->
<cache name="passwordRetryCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>
</ehcache>
shiro-multirealm.ini
[main]
realm1=com.java.shiro.realm.MyRealm1
realm2=com.java.shiro.realm.MyRealm2
realm3=com.java.shiro.realm.MyRealm3
securityManager.realms=$realm1,$realm2,$realm3
shiro.ini
[main]
credentialsMatcher=com.java.shiro.credentials.RetryLimitHashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=md5
credentialsMatcher.hashIterations=2
credentialsMatcher.storedCredentialsHexEncoded=true
userRealm=com.java.shiro.realm.UserRealm
userRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$userRealm
10、测试
package BaseTest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.apache.shiro.util.ThreadContext;
import org.junit.After;
import org.junit.Before;
import com.java.shiro.entity.Permission;
import com.java.shiro.entity.Role;
import com.java.shiro.entity.User;
import com.java.shiro.service.PermissionService;
import com.java.shiro.service.RoleService;
import com.java.shiro.service.UserService;
import com.java.shiro.service.impl.PermissionServiceImpl;
import com.java.shiro.service.impl.RoleServiceImpl;
import com.java.shiro.service.impl.UserServiceImpl;
import com.java.shiro.util.JdbcTemplateUtils;
import org.apache.shiro.mgt.SecurityManager;
public class BaseTest {
protected PermissionService permissionService = new PermissionServiceImpl();
protected RoleService roleService = new RoleServiceImpl();
protected UserService userService = new UserServiceImpl();
protected String password = "123";
protected Permission p1;
protected Permission p2;
protected Permission p3;
protected Role r1;
protected Role r2;
protected User u1;
protected User u2;
protected User u3;
protected User u4;
@Before
public void setUp() {
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_users");
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_roles");
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_permissions");
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_users_roles");
JdbcTemplateUtils.jdbcTemplate().update("delete from sys_roles_permissions");
//1、新增权限
p1 = new Permission("user:create", "用户模块新增", Boolean.TRUE);
p2 = new Permission("user:update", "用户模块修改", Boolean.TRUE);
p3 = new Permission("menu:create", "菜单模块新增", Boolean.TRUE);
permissionService.createPermission(p1);
permissionService.createPermission(p2);
permissionService.createPermission(p3);
//2、新增角色
r1 = new Role("admin", "管理员", Boolean.TRUE);
r2 = new Role("user", "用户管理员", Boolean.TRUE);
roleService.createRole(r1);
roleService.createRole(r2);
//3、关联角色-权限
roleService.correlationPermissions(r1.getId(), p1.getId());
roleService.correlationPermissions(r1.getId(), p2.getId());
roleService.correlationPermissions(r1.getId(), p3.getId());
roleService.correlationPermissions(r2.getId(), p1.getId());
roleService.correlationPermissions(r2.getId(), p2.getId());
//4、新增用户
u1 = new User("zhang", password);
u2 = new User("li", password);
u3 = new User("wu", password);
u4 = new User("wang", password);
u4.setLocked(Boolean.TRUE);
userService.createUser(u1);
userService.createUser(u2);
userService.createUser(u3);
userService.createUser(u4);
//5、关联用户-角色
userService.correlationRoles(u1.getId(), r1.getId());
}
@After
public void tearDown() throws Exception {
ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响
}
protected void login(String configFile, String username, String password) {
//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory(configFile);
//2、得到SecurityManager实例 并绑定给SecurityUtils
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
subject.login(token);
}
public Subject subject() {
return SecurityUtils.getSubject();
}
}
package realm;
import java.util.Collection;
import java.util.Set;
import junit.framework.Assert;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import com.java.shiro.entity.User;
import BaseTest.BaseTest;
public class PrincialCollectionTest extends BaseTest{
@Test
public void test() {
//因为Realm里没有进行验证,所以相当于每个Realm都身份验证成功了
login("classpath:shiro-multirealm.ini", "zhang", "123");
Subject subject = subject();
//获取Primary Principal(即第一个)
Object primaryPrincipal1 = subject.getPrincipal();
PrincipalCollection princialCollection = subject.getPrincipals();
Object primaryPrincipal2 = princialCollection.getPrimaryPrincipal();
//但是因为多个Realm都返回了Principal,所以此处到底是哪个是不确定的
Assert.assertEquals(primaryPrincipal1, primaryPrincipal2);
//返回 a b c
Set<String> realmNames = princialCollection.getRealmNames();
System.out.println(realmNames);
//因为MyRealm1和MyRealm2返回的凭据都是zhang,所以排重了
Set<Object> principals = princialCollection.asSet(); //asList和asSet的结果一样
System.out.println(principals);
//根据Realm名字获取
Collection<User> users = princialCollection.fromRealm("c");
System.out.println(users);
}
}
package realm;
import junit.framework.Assert;
import org.junit.Test;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import BaseTest.BaseTest;
public class UserRealmTest extends BaseTest{
@Test
public void testLoginSuccess() {
login("classpath:shiro.ini", u1.getUsername(), password);
Assert.assertTrue(subject().isAuthenticated());
}
@Test(expected = UnknownAccountException.class)
public void testLoginFailWithUnknownUsername() {
login("classpath:shiro.ini", u1.getUsername() + "1", password);
}
@Test(expected = IncorrectCredentialsException.class)
public void testLoginFailWithErrorPassowrd() {
login("classpath:shiro.ini", u1.getUsername(), password + "1");
}
@Test(expected = LockedAccountException.class)
public void testLoginFailWithLocked() {
login("classpath:shiro.ini", u4.getUsername(), password + "1");
}
@Test(expected = ExcessiveAttemptsException.class)
public void testLoginFailWithLimitRetryCount() {
for(int i = 1; i <= 5; i++) {
try {
login("classpath:shiro.ini", u3.getUsername(), password + "1");
} catch (Exception e) {/*ignore*/}
}
login("classpath:shiro.ini", u3.getUsername(), password + "1");
//需要清空缓存,否则后续的执行就会遇到问题(或者使用一个全新账户测试)
}
@Test
public void testHasRole() {
login("classpath:shiro.ini", u1.getUsername(), password );
Assert.assertTrue(subject().hasRole("admin"));
}
@Test
public void testNoRole() {
login("classpath:shiro.ini", u2.getUsername(), password);
Assert.assertFalse(subject().hasRole("admin"));
}
@Test
public void testHasPermission() {
login("classpath:shiro.ini", u1.getUsername(), password);
Assert.assertTrue(subject().isPermittedAll("user:create", "menu:create"));
}
@Test
public void testNoPermission() {
login("classpath:shiro.ini", u2.getUsername(), password);
Assert.assertFalse(subject().isPermitted("user:create"));
}
}
package service;
import java.util.Set;
import junit.framework.Assert;
import org.junit.Test;
import BaseTest.BaseTest;
public class ServiceTest extends BaseTest {
@Test
public void testUserRolePermissionRelation() {
//zhang
Set<String> roles = userService.findRoles(u1.getUsername());
Assert.assertEquals(1, roles.size());
Assert.assertTrue(roles.contains(r1.getRole()));
Set<String> permissions = userService.findPermissions(u1.getUsername());
Assert.assertEquals(3, permissions.size());
Assert.assertTrue(permissions.contains(p3.getPermission()));
//li
roles = userService.findRoles(u2.getUsername());
Assert.assertEquals(0, roles.size());
permissions = userService.findPermissions(u2.getUsername());
Assert.assertEquals(0, permissions.size());
//解除 admin-menu:update关联
roleService.uncorrelationPermissions(r1.getId(), p3.getId());
permissions = userService.findPermissions(u1.getUsername());
Assert.assertEquals(2, permissions.size());
Assert.assertFalse(permissions.contains(p3.getPermission()));
//删除一个permission
permissionService.deletePermission(p2.getId());
permissions = userService.findPermissions(u1.getUsername());
Assert.assertEquals(1, permissions.size());
//解除 zhang-admin关联
userService.uncorrelationRoles(u1.getId(), r1.getId());
roles = userService.findRoles(u1.getUsername());
Assert.assertEquals(0, roles.size());
}
}
这是根据《跟我学shiro》写的代码,觉得挺有用的。
到此结束啦~~