使用shiro之前肯定要导入相关的依赖 <!-- shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.5.3</version> </dependency> <!--thymeleaf-shiro整合--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
说明:最后一个是thymeleaf的整合包,前端如果需要使用标签就需要这个包。
使用shiro验证用户登录 数据库表说明:密码是使用盐值加密进行处理后存放在数据库中的,salt是盐值。
spring-shiro.xml配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans "> <!--url过滤器--> <bean/> <!-- 登出出过滤器 --> <bean> <property value="http://www.likecs.com/"/> </bean> <!--配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 --> <bean> <!-- 调用我们配置的权限管理器 --> <property ref="securityManager"/> <!-- 配置我们的登录请求地址 --> <property value="/router/toLogin"/> <!-- 如果您请求的资源不再您的权限范围,则跳转到/403请求地址 --> <property value="/router/nopower"/> <!-- 过滤器 --> <property> <util:map> <entry key="logout" value-ref="logoutFilter"/> <entry key="url" value-ref="urlPathMatchingFilter"/> </util:map> </property> <!-- 权限配置 --> <property> <value> <!-- anon表示此地址不需要任何权限即可访问 --> /=anon /static/**=anon /router/*=anon /*.html=anon /login.do=anon /register.do=anon /logout=logout <!--/staff/**=authc--> <!-- 所有的请求(除去配置的静态资源请求或请求地址为anon的请求)都要通过登录验证,如果未登录则跳到/login --> /**=url </value> </property> </bean> <!-- 会话ID生成器 --> <bean/> <!-- 会话Cookie模板 关闭浏览器立即失效 --> <bean> <constructor-arg value="sid"/> <property value="true"/> <property value="-1"/> </bean> <!-- 会话DAO --> <bean> <property ref="sessionIdGenerator"/> </bean> <!-- 会话验证调度器,每30分钟执行一次验证 ,设定会话超时及保存 --> <bean> <property value="1800000"/> <property ref="sessionManager"/> </bean> <!-- 会话管理器 --> <bean> <!-- 全局会话超时时间(单位毫秒),默认30分钟 --> <property value="1800000"/> <property value="true"/> <property value="true"/> <property ref="sessionValidationScheduler"/> <property ref="sessionDAO"/> <property value="true"/> <property ref="sessionIdCookie"/> </bean> <!-- 安全管理器 --> <bean> <property ref="databaseRealm"/> <property ref="sessionManager"/> </bean> <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --> <bean> <property value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property ref="securityManager"/> </bean> <!-- 密码匹配器,自动校验密码 --> <bean> <property value="md5"/> <property value="1"/> <property value="true"/> </bean> <!--注入DatabaseRealm类--> <bean> <property ref="credentialsMatcher"/> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean/> </beans>注意/**=url要放在最后面,如果放在前面就先执行的url过滤,静态资源和开放权限的跳转会失效。
shiroUtil(对密码进行加密) import org.apache.shiro.crypto.SecureRandomNumberGenerator; import org.apache.shiro.crypto.hash.SimpleHash; public class ShiroUtil { public static String encryptPassword(String password, String salt) { // 在这里更改密码规则后还要在applicationContext-shiro.xml中改密码匹配器 return new SimpleHash("md5", password, salt, 1).toString(); } public static String generateSalt() { return new SecureRandomNumberGenerator().nextBytes().toString(); } } 写核心的授权验证realm package ; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; 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.context.annotation.Bean; import ; import ; import ; import ; import java.util.Set; //自定义Realm public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; @Autowired private PermService permService; @Autowired private RoleService roleService; //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //账号已经通过验证了 String userName =(String) principalCollection.getPrimaryPrincipal(); System.out.println("授权中得到的userName:"+userName); //通过service获取角色和权限 Set<String> permissions = permService.getPerms(userName); Set<String> roles = roleService.getRoles(userName); //授权对象 SimpleAuthorizationInfo s = new SimpleAuthorizationInfo(); //把通过service获取到的角色和权限放进去 s.setStringPermissions(permissions); s.setRoles(roles); return s; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了认证+===》doGetAuthenticationInfo"); // 获取名字 String name = token.getPrincipal().toString(); System.out.println(name); // 获取user User admin = userService.loginByName(name); if (admin == null){ return null; } String passwordInDB = admin.getUser_password(); String salt = admin.getSalt(); return new SimpleAuthenticationInfo(name, passwordInDB, ByteSource.Util.bytes(salt), getName()); // getName()是realm的继承方法,返回当前类名DatabaseRealm // 通过applicationContext-shiro.xml中的HashedCredentialsMatcher,进行密码的自动校验 } } 登录以及注册控制 @RequestMapping(value="/login.do",method = RequestMethod.POST) public String loginControl(String username, String password, Model model){ //获取当前用户,shiro包下的 Subject subject = SecurityUtils.getSubject(); //封装用户的登录数据 UsernamePasswordToken token = new UsernamePasswordToken(username, password); //执行登录方法 try { subject.login(token);//执行登录,在用户认证的里面去认证用户名和密码 Session session=subject.getSession(); session.setAttribute("subject", subject); return "redirect:/router/toIndex";//登录通过转到首页 }catch (UnknownAccountException e){//用户名不存在 model.addAttribute("msg","用户名不存在"); return "login"; }catch (IncorrectCredentialsException e){//密码不存在 model.addAttribute("msg","密码错误啊"); return "login"; } } @RequestMapping(value = "/register.do",method = RequestMethod.POST) public String register(String user_id,String user_name,String user_password,String user_phone,Model model){ User user = new User(); user.setUser_id(Integer.parseInt(user_id)); user.setUser_name(user_name); user.setUser_password(user_password); user.setUser_phone(user_phone); String salt = new Random().nextInt(1000000)+"";//通过随机数来设置盐值 user.setSalt(salt); String encryptPassword = ShiroUtil.encryptPassword(user.getUser_password(), user.getSalt());//将密码和盐值混合加密 user.setUser_password(encryptPassword); int register = userService.register(user); if (register > 0){ //进行角色分配,注册的角色都设置为普通用户 int i = roleService.addRole(user.getUser_id()); if (i <= 0){ model.addAttribute("msg","账号注册成功!角色分配失败,请联系管理要换进行权限分配!"); System.out.println("角色分配失败!请手动进行分配!"); } model.addAttribute("msg","注册成功!"); return "login"; }else{ return "login"; } }