标签:apache ica form second action == 访问 idle odi
JavaSE应用中使用
web应用中使用
SSM整合Shiro(配置多,用的少)
SpringBoot应用整合Shiro
lombok
spring web
thymeleaf
依赖
<!-- druid starter --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!--mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency>
spring:
datasource:
druid:
url: jdbc:mysql://47.96.11.185:3306/test
# MySQL如果是8.x com.mysql.cj.jdbc.Driver
driver-class-name: com.mysql.jdbc.Driver
username: root
password: admin123
initial-size: 1
min-idle: 1
max-active: 20
mybatis:
mapper-locations: classpath:mappers/*Mapper.xml
type-aliases-package: com.qfedu.springbootssm.beans
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency>
@Configuration public class ShiroConfig { @Bean public JdbcRealm getJdbcRealm(DataSource dataSource){ JdbcRealm jdbcRealm = new JdbcRealm(); //JdbcRealm会自行从数据库查询用户及权限数据(数据库的表结构要符合JdbcRealm的规范) jdbcRealm.setDataSource(dataSource); //JdbcRealm默认开启认证功能,需要手动开启授权功能 jdbcRealm.setPermissionsLookupEnabled(true); return jdbcRealm; } @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(JdbcRealm jdbcRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(jdbcRealm); return securityManager; } @Bean public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean(); //过滤器就是shiro就行权限校验的核心,进行认证和授权是需要SecurityManager的 filter.setSecurityManager(securityManager); Map<String,String> filterMap = new HashMap<>(); filterMap.put("/","anon"); filterMap.put("/login.html","anon"); filterMap.put("/regist.html","anon"); filterMap.put("/user/login","anon"); filterMap.put("/user/regist","anon"); filterMap.put("/static/**","anon"); filterMap.put("/**","authc"); filter.setFilterChainDefinitionMap(filterMap); filter.setLoginUrl("/login.html"); //设置未授权访问的页面路径 filter.setUnauthorizedUrl("/login.html"); return filter; } }
@Service public class UserServiceImpl { public void checkLogin(String userName,String userPwd) throws Exception{ Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd); subject.login(token); } }
UserController.java
@Controller @RequestMapping("user") public class UserController { @Resource private UserServiceImpl userService; @RequestMapping("login") public String login(String userName,String userPwd){ try { userService.checkLogin(userName,userPwd); System.out.println("------登录成功!"); return "index"; } catch (Exception e) { System.out.println("------登录失败!"); return "login"; } } }
/** * 1.创建一个类继承AuthorizingRealm类(实现了Realm接口的类) * 2.重写doGetAuthorizationInfo和doGetAuthenticationInfo方法 * 3.重写getName方法返回当前realm的一个自定义名称 */ public class MyRealm extends AuthorizingRealm { @Resource private UserDAO userDAO; @Resource private RoleDAO roleDAO; @Resource private PermissionDAO permissionDAO; public String getName() { return "myRealm"; } /** * 获取授权数据(将当前用户的角色及权限信息查询出来) */ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //获取用户的用户名 String username = (String) principalCollection.iterator().next(); //根据用户名查询当前用户的角色列表 Set<String> roleNames = roleDAO.queryRoleNamesByUsername(username); //根据用户名查询当前用户的权限列表 Set<String> ps = permissionDAO.queryPermissionsByUsername(username); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roleNames); info.setStringPermissions(ps); return info; } /** * 获取认证的安全数据(从数据库查询的用户的正确数据) */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //参数authenticationToken就是传递的 subject.login(token) // 从token中获取用户名 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); //根据用户名,从数据库查询当前用户的安全数据 User user = userDAO.queryUserByUsername(username); AuthenticationInfo info = new SimpleAuthenticationInfo( username, //当前用户用户名 user.getUserPwd(), //从数据库查询出来的安全密码 getName()); return info; } }
明文-----(加密规则)-----密文
加密规则可以自定义,在项目开发中我们通常使用BASE64和MD5编码方式
BASE64:可反编码的编码方式(对称)
明文----密文
密文----明文
MD5: 不可逆的编码方式(非对称)
明文----密文
如果数据库用户的密码存储的密文,Shiro该如何完成验证呢?
使用Shiro提供的加密功能,对输入的密码进行加密之后再进行认证。
@Configuration public class ShiroConfig { //... @Bean public HashedCredentialsMatcher getHashedCredentialsMatcher(){ HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); //matcher就是用来指定加密规则 //加密方式 matcher.setHashAlgorithmName("md5"); //hash次数 matcher.setHashIterations(1); //此处的循环次数要与用户注册是密码加密次数一致 return matcher; } //自定义Realm @Bean public MyRealm getMyRealm( HashedCredentialsMatcher matcher ){ MyRealm myRealm = new MyRealm(); myRealm.setCredentialsMatcher(matcher); return myRealm; } //... }
<form action="/user/regist" method="post"> <p>帐号:<input type="text" name="userName"/></p> <p>密码:<input type="text" name="userPwd"/></p> <p><input type="submit" value="提交注册"/></p> </form>
UserController
@Controller @RequestMapping("user") public class UserController { @Resource private UserServiceImpl userService; @RequestMapping("/regist") public String regist(String userName,String userPwd) { System.out.println("------注册"); //注册的时候要对密码进行加密存储 Md5Hash md5Hash = new Md5Hash(userPwd); System.out.println("--->>>"+ md5Hash.toHex()); //加盐加密 int num = new Random().nextInt(90000)+10000; //10000—99999 String salt = num+""; Md5Hash md5Hash2 = new Md5Hash(userPwd,salt); System.out.println("--->>>"+md5Hash2); //加盐加密+多次hash Md5Hash md5Hash3 = new Md5Hash(userPwd,salt,3); System.out.println("--->>>"+md5Hash3); //SimpleHash hash = new SimpleHash("md5",userPwd,num,3); //将用户信息保存到数据库时,保存加密后的密码,如果生成的随机盐,盐也要保存 return "login"; } }
在自定义Realm中:
public class MyRealm extends AuthorizingRealm { @Resource private UserDAO userDAO; @Resource private RoleDAO roleDAO; @Resource private PermissionDAO permissionDAO; public String getName() { return "myRealm"; } /** * 获取认证的安全数据(从数据库查询的用户的正确数据) */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //参数authenticationToken就是传递的 subject.login(token) // 从token中获取用户名 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); //根据用户名,从数据库查询当前用户的安全数据 User user = userDAO.queryUserByUsername(username); // AuthenticationInfo info = new SimpleAuthenticationInfo( // username, //当前用户用户名 // user.getUserPwd(), //从数据库查询出来的安全密码 // getName()); //如果数据库中用户的密码是加了盐的 AuthenticationInfo info = new SimpleAuthenticationInfo( username, //当前用户用户名 user.getUserPwd(), //从数据库查询出来的安全密码 ByteSource.Util.bytes(user.getPwdSalt()), getName()); return info; } }
filterMap.put("/exit","logout");
在页面的“退出”按钮上,跳转到logout对应的url
<a href="exit">退出</a>
用户登录成功之后,要进行响应的操作就需要有对应的权限;在进行操作之前对权限进行检查—授权
权限控制通常有两类做法:
不同身份的用户登录,我们现在不同的操作菜单(没有权限的菜单不现实)
对所有用户显示所有菜单,当用户点击菜单以后再验证当前用户是否有此权限,如果没有则提示权限不足
在菜单页面只显示当前用户拥有权限操作的菜单
shiro标签
<shiro:hasPermission name="sys:c:save"> <dd><a href="javascript:;">入库</a></dd> </shiro:hasPermission>
filterMap.put("/c_add.html","perms[sys:c:save]"); //设置未授权访问的页面路径—当权限不足时显示此页面 filter.setUnauthorizedUrl("/lesspermission.html");
配置Spring对Shiro注解的支持:ShiroConfig.java
@Bean public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); autoProxyCreator.setProxyTargetClass(true); return autoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor( DefaultWebSecurityManager securityManager){ AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; }
@Controller @RequestMapping("customer") public class CustomerController { @RequestMapping("list") //如果没有 sys:k:find 权限,则不允许执行此方法 @RequiresPermissions("sys:k:find") // @RequiresRoles("") public String list(){ System.out.println("----------->查询客户信息"); return "customer_list"; } }
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler public String doException(Exception e){ if(e instanceof AuthorizationException){ return "lesspermission"; } return null; } }
在代码中进行手动的权限校验
Subject subject = SecurityUtils.getSubject(); if(subject.isPermitted("sys:k:find")){ System.out.println("----------->查询客户信息"); return "customer_list"; }else{ return "lesspermission"; }
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.4.0</version> </dependency>
<?xml version="1.0" encoding="UTF-8"?> <ehcache updateCheck="false" dynamicConfig="false"> <diskStore path="C:\TEMP" /> <cache name="users" timeToLiveSeconds="300" maxEntriesLocalHeap="1000"/> <defaultCache name="defaultCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" maxElementsOnDisk="100000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"/> <!--缓存淘汰策略:当缓存空间比较紧张时,我们要存储新的数据进来,就必然要删除一些老的数据 LRU 最近最少使用 FIFO 先进先出 LFU 最少使用 --> </ehcache>
@Bean public EhCacheManager getEhCacheManager(){ EhCacheManager ehCacheManager = new EhCacheManager(); ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml"); return ehCacheManager; } @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm); securityManager.setCacheManager(getEhCacheManager()); return securityManager; }
自定义session管理器
将自定义的session管理器设置给SecurityManager
@Bean public DefaultWebSessionManager getDefaultWebSessionManager(){ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); System.out.println("----------"+sessionManager.getGlobalSessionTimeout()); // 1800000 //配置sessionManager sessionManager.setGlobalSessionTimeout(5*60*1000); return sessionManager; } @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm); securityManager.setCacheManager(getEhCacheManager()); securityManager.setSessionManager(getDefaultWebSessionManager()); return securityManager; }
未认证—可访问的页面—(陌生人)—问候
login.html、regist.html
记住我—可访问的页面—(前女友)—朋友间的拥抱
info.html
已认证—可访问的页面—(现女友)—牵手
// anon 表示未认证可访问的url // user 表示记住我可访问的url(已认证也可以访问) //authc 表示已认证可访问的url //perms 表示必须具备指定的权限才可访问 //logout 表示指定退出的url filterMap.put("/","anon"); filterMap.put("/index.html","user"); filterMap.put("/login.html","anon"); filterMap.put("/regist.html","anon"); filterMap.put("/user/login","anon"); filterMap.put("/user/regist","anon"); filterMap.put("/layui/**","anon"); filterMap.put("/**","authc"); filterMap.put("/c_add.html","perms[sys:c:save]"); filterMap.put("/exit","logout");
@Bean public CookieRememberMeManager cookieRememberMeManager(){ CookieRememberMeManager rememberMeManager = new CookieRememberMeManager(); //cookie必须设置name SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setMaxAge(30*24*60*60); rememberMeManager.setCookie(cookie); return rememberMeManager; } @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm); securityManager.setCacheManager(getEhCacheManager()); securityManager.setSessionManager(getDefaultWebSessionManager()); //设置remember管理器 securityManager.setRememberMeManager(cookieRememberMeManager()); return securityManager; }
<form action="/user/login" method="post"> <p>帐号:<input type="text" name="userName"/></p> <p>密码:<input type="text" name="userPwd"/></p> <p>记住我:<input type="checkbox" name="rememberMe"/></p> <p><input type="submit" value="登录"/></p> </form>
@Controller @RequestMapping("user") public class UserController { @Resource private UserServiceImpl userService; @RequestMapping("login") public String login(String userName,String userPwd,boolean rememberMe){ try { userService.checkLogin(userName,userPwd,rememberMe); System.out.println("------登录成功!"); return "index"; } catch (Exception e) { System.out.println("------登录失败!"); return "login"; } } //... }
@Service public class UserServiceImpl { public void checkLogin(String userName, String userPwd,boolean rememberMe) throws Exception { //Shiro进行认证 ——入口 Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd); token.setRememberMe(rememberMe); subject.login(token); } }
当shiro进行权限管理,数据来自于不同的数据源时,我们可以给SecurityManager配置多个Realm
多个Realm依次进行认证
根据不同的条件从多个Realm中选择一个进行认证处理
定义多个Realm
UserRealm
public class UserRealm extends AuthorizingRealm { Logger logger = LoggerFactory.getLogger(UserRealm.class); @Override public String getName() { return "UserRealm"; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { logger.info("--------------------------------UserRealm"); //从token中获取username UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); //根据username从users表中查询用户信息 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,"123456",getName()); return info; } }
public class ManagerRealm extends AuthorizingRealm { Logger logger = LoggerFactory.getLogger(ManagerRealm.class); @Override public String getName() { return "ManagerRealm"; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { logger.info("--------------------------------ManagerRealm"); //从token中获取username UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); //根据username从吗managers表中查询用户信息 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,"222222",getName()); return info; } }
@Configuration public class ShiroConfig { @Bean public UserRealm userRealm(){ UserRealm userRealm = new UserRealm(); return userRealm; } @Bean public ManagerRealm managerRealm(){ ManagerRealm managerRealm = new ManagerRealm(); return managerRealm; } @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //securityManager中配置多个realm Collection<Realm> realms = new ArrayList<>();
realms.add(userRealm()); realms.add(managerRealm());
securityManager.setRealms(realms); return securityManager; } //... }
自定义Realm(UserRealm\ManagerRealm)
当在登录页面选择“普通用户”登录,则执行UserRealm的认证
当在登录页面选择“管理员”登录,则执行ManagerRealm的认证
Realm的声明及配置
public class MyToken extends UsernamePasswordToken { private String loginType; public MyToken(String userName,String userPwd, String loginType) { super(userName,userPwd); this.loginType = loginType; } public String getLoginType() { return loginType; } public void setLoginType(String loginType) { this.loginType = loginType; } }
public class MyModularRealmAuthenticator extends ModularRealmAuthenticator { Logger logger = LoggerFactory.getLogger(MyModularRealmAuthenticator.class); @Override protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { logger.info("------------------------------MyModularRealmAuthenticator"); this.assertRealmsConfigured(); Collection<Realm> realms = this.getRealms(); MyToken token = (MyToken) authenticationToken; String loginType = token.getLoginType(); // User logger.info("------------------------------loginType:"+loginType); Collection<Realm> typeRealms = new ArrayList<>(); for(Realm realm:realms){ if(realm.getName().startsWith(loginType)){ //UserRealm typeRealms.add(realm); } } if(typeRealms.size()==1){ return this.doSingleRealmAuthentication((Realm)typeRealms.iterator().next(), authenticationToken); }else{ return this.doMultiRealmAuthentication(typeRealms, authenticationToken); } } }
@Configuration public class ShiroConfig { @Bean public UserRealm userRealm(){ UserRealm userRealm = new UserRealm(); return userRealm; } @Bean public ManagerRealm managerRealm(){ ManagerRealm managerRealm = new ManagerRealm(); return managerRealm; } @Bean public MyModularRealmAuthenticator myModularRealmAuthenticator(){ MyModularRealmAuthenticator myModularRealmAuthenticator = new MyModularRealmAuthenticator(); return myModularRealmAuthenticator; } @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //配置自定义认证器(放在realms设置之前) securityManager.setAuthenticator(myModularRealmAuthenticator()); //securityManager中配置多个realm Collection<Realm> realms = new ArrayList<>(); realms.add(userRealm()); realms.add(managerRealm()); securityManager.setRealms(realms); return securityManager; } //... }
<form action="user/login" method="post"> <p>帐号:<input type="text" name="userName"/></p> <p>密码:<input type="text" name="userPwd"/></p> <p><input type="radio" name="loginType" value="User" checked/>普通用户 <input type="radio" name="loginType" value="Manager"/>管理员</p> <p><input type="submit" value="登录"/></p> </form>
@Controller @RequestMapping("user") public class UserController { Logger logger = LoggerFactory.getLogger(UserController.class); @RequestMapping("login") public String login(String userName,String userPwd, String loginType){ logger.info("~~~~~~~~~~~~~UserController-login"); try{ //UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd); MyToken token = new MyToken(userName,userPwd,loginType); Subject subject = SecurityUtils.getSubject(); subject.login(token); return "index"; }catch (Exception e){ return "login"; } } }
标签:apache ica form second action == 访问 idle odi
原文地址:https://www.cnblogs.com/jikeyi/p/13375167.html