文章目录
- 整合思路
- 1.创建springboot项目
- 2.引入依赖
- 3.创建Shiro Filter
- 0.创建配置类
- 1.配置shiroFilterFactoryBean
- 2.配置WebSecurityManager
- 3.创建自定义Relm
- 4.配置自定义realm
- 5.编写控制器跳转至index.html
- 6.加入资源的权限控制
- 7. 常见过滤器
- 登录认证实现
- 登录界面
- 开发controller
- 开发realm中返回静态数据(未连接数据库)
- 退出认证实现
- 页面按钮
- 开发Controller
- MD5、Salt的认证实现
- 开发数据库注册
- 1.用户注册页面
- 2.创建用户注册表
- 3.引入依赖
- 4.配置数据源
- 5.创建实体类
- 6.开发controller
- 7.开发Service
- 8.创建DAO接口
- 9.创建salt工具类
- 开发数据库注册认证
- 1.开发DAO
- 2.开发Service层
- 3.开发在工厂中获取bean对象的工具类
- 4.修改自定义realm
- 5.修改ShiroConfig中realm使用凭证匹配器以及hash散列
整合思路
1.创建springboot项目
2.引入依赖
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.5.3</version>
</dependency>
3.创建Shiro Filter
0.创建配置类
1.配置shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){//创建shiro的filterShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//注入安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);return shiroFilterFactoryBean;
}
2.配置WebSecurityManager
@Bean
public DefaultWebSecurityManager getSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager;
}
3.创建自定义Relm
public class CustomerRealm extends AuthorizingRealm {//处理授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}//处理认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {return null;}
}
4.配置自定义realm
//创建自定义realm
@Bean
public Realm getRealm(){return new CustomerRealm();
}
5.编写控制器跳转至index.html
@Controller
public class IndexController {@RequestMapping("index")public String index(){System.out.println("跳转至主页");return "index";}
}
6.加入资源的权限控制
修改ShiroFilterFactoryBean配置
//注入安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map = new LinkedHashMap<>();
map.put("/**","authc");
//配置认证和授权规则
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
/** 代表拦截项目中一切资源 authc 代表shiro中的一个filter的别名,详细内容看文档的shirofilter列表
7. 常见过滤器
- 注意: shiro提供和多个默认的过滤器,我们可以用这些过滤器来配置控制指定url的权限:
配置缩写 | 对应的过滤器 | 功能 |
---|---|---|
anon | AnonymousFilter | 指定url可以匿名访问 |
authc | FormAuthenticationFilter | 指定url需要form表单登录,默认会从请求中获取username 、password ,rememberMe 等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。 |
authcBasic | BasicHttpAuthenticationFilter | 指定url需要basic登录 |
logout | LogoutFilter | 登出过滤器,配置指定url就可以实现退出功能,非常方便 |
noSessionCreation | NoSessionCreationFilter | 禁止创建会话 |
perms | PermissionsAuthorizationFilter | 需要指定权限才能访问 |
port | PortFilter | 需要指定端口才能访问 |
rest | HttpMethodPermissionFilter | 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释 |
roles | RolesAuthorizationFilter | 需要指定角色才能访问 |
ssl | SslFilter | 需要https请求才能访问 |
user | UserFilter | 需要已登录或“记住我”的用户才能访问 |
登录认证实现
登录界面
<form action="${pageContext.request.contextPath}/user/login" method="post">用户名:<input type="text" name="username" > <br/>密码 : <input type="text" name="password"> <br><input type="submit" value="登录">
</form>
开发controller
@Controller
@RequestMapping("user")
public class UserController {/*** 用来处理身份认证* @param username* @param password* @return*/@RequestMapping("login")public String login(String username,String password){//获取主体对象Subject subject = SecurityUtils.getSubject();try {subject.login(new UsernamePasswordToken(username,password));return "redirect:/index.jsp";} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户名错误!");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误!");}return "redirect:/login.jsp";}
}
开发realm中返回静态数据(未连接数据库)
@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("==========================");String principal = (String) token.getPrincipal();if("xiaochen".equals(principal)){return new SimpleAuthenticationInfo(principal,"123",this.getName());}return null;}
}
退出认证实现
页面按钮
<a href="${pageContext.request.contextPath}/user/logout">退出用户</a>
开发Controller
@Controller
@RequestMapping("user")
public class UserController {/*** 退出登录**/@RequestMapping("logout")public String logout(){Subject subject = SecurityUtils.getSubject();subject.logout();//退出用户return "redirect:/login.jsp";}
}
MD5、Salt的认证实现
开发数据库注册
1.用户注册页面
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/user/register" method="post">用户名:<input type="text" name="username" > <br/>密码 : <input type="text" name="password"> <br><input type="submit" value="立即注册">
</form>
2.创建用户注册表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (`id` int(6) NOT NULL AUTO_INCREMENT,`username` varchar(40) DEFAULT NULL,`password` varchar(40) DEFAULT NULL,`salt` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
3.引入依赖
<!--mybatis相关依赖-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.2</version>
</dependency><!--mysql-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency><!--druid-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.19</version>
</dependency>
4.配置数据源
server.port=8888
server.servlet.context-path=/shiro
spring.application.name=shirospring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
#新增配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=rootmybatis.type-aliases-package=com.baizhi.springboot_jsp_shiro.entity
mybatis.mapper-locations=classpath:com/baizhi/mapper/*.xml
5.创建实体类
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {private String id;private String username;private String password;private String salt;//定义角色集合private List<Role> roles;}
6.开发controller
@Controller
@RequestMapping("user")
public class UserController {@Autowiredprivate UserService userService;/*** 用户注册*/@RequestMapping("register")public String register(User user) {try {userService.register(user);return "redirect:/login.jsp";}catch (Exception e){e.printStackTrace();return "redirect:/register.jsp";}}
}
7.开发Service
public interface UserService {//注册用户方法void register(User user);
}
@Overridepublic void register(User user) {//处理业务调用dao//1.生成随机盐String salt = SaltUtils.getSalt(8);//2.将随机盐保存到数据user.setSalt(salt);//3.明文密码进行md5 + salt + hash散列Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);user.setPassword(md5Hash.toHex());userDAO.save(user);}
8.创建DAO接口
@Mapper
public interface UserDAO {void save(User user);
}
<insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">insert into t_user values(#{id},#{username},#{password},#{salt})
</insert>
9.创建salt工具类
public class SaltUtils {/*** 生成salt的静态方法* @param n* @return*/public static String getSalt(int n){char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();StringBuilder sb = new StringBuilder();for (int i = 0; i < n; i++) {char aChar = chars[new Random().nextInt(chars.length)];sb.append(aChar);}return sb.toString();}
}
开发数据库注册认证
我们需要根据用户名查询来判定用户注册的操作是否合法
1.开发DAO
@Mapper
public interface UserDAO {void save(User user);//根据身份信息认证的方法User findByUserName(String username);
}
<select id="findByUserName" parameterType="String" resultType="User">select id,username,password,salt from t_userwhere username = #{username}
</select>
2.开发Service层
public interface UserService {//注册用户方法void register(User user);//根据用户名查询业务的方法User findByUserName(String username);
}
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {@Autowiredprivate UserDAO userDAO;@Overridepublic User findByUserName(String username) {return userDAO.findByUserName(username);}
}
3.开发在工厂中获取bean对象的工具类
解决给自定义的Realm注入业务对象。
@Component
public class ApplicationContextUtils implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context = applicationContext;}//根据bean名字获取工厂中指定bean 对象public static Object getBean(String beanName){return context.getBean(beanName);}
}
4.修改自定义realm
@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("==========================");//根据身份信息String principal = (String) token.getPrincipal();//在工厂中获取service对象UserService userService = (UserService) ApplicationContextUtils.getBean("userService");//根据身份信息查询User user = userService.findByUserName(principal);if(!ObjectUtils.isEmpty(user)){//返回数据库信息return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());}return null;}
5.修改ShiroConfig中realm使用凭证匹配器以及hash散列
@Bean
public Realm getRealm(){CustomerRealm customerRealm = new CustomerRealm();//设置hashed凭证匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//设置md5加密credentialsMatcher.setHashAlgorithmName("md5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);return customerRealm;
}