将用户对页面访问的权限分为三个级别:
未认证—可访问的页面—(陌生人)—问候
login.html、regist.html
记住我—可访问的页面—(前女友)—朋友间的拥抱
info.html
已认证—可访问的页面—(现女友)—牵手
转账.html
2.1 在过滤器中设置“记住我”可访问的url
// anon 表示未认证可访问的url
// user 表示记住我可访问的url(已认证也可以访问),例如某些页面在之前登陆过,安全级别又不高时,可以在用户再次浏览时呈现,这时可以设置为user
//authc 表示已认证可访问的url,对于某些安全级别很高的,即使几天或几小时之前登陆过,但是在再次进行操作时还必须得确认登陆或安全性时,比如付款时再次确认用户身份,这时可以设置为authc
//perms 表示必须具备指定的权限才可访问
//logout 表示指定退出的url
filterMap.put("/","anon");
// 为user表示"记住我",但是当用户需要一些其他的认证才能访问时,必须要进行验证才能访问
// user要比authc低一等级
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");
2.2 在ShiroConfig.java中配置基于cookie的rememberMe管理器
@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;
}
2.3 登录认证时设置token“记住我”
登录页面
控制器
@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
@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);
}
}
3.1 使用场景
当shiro进行权限管理,数据来自于不同的数据源时,我们可以给SecurityManager配置多个Realm
|
3.2 多个Realm的处理方式
3.2.1 链式处理
多个Realm依次进行认证,只要有一个Realm认证成功就表示认证成功,但是每次都要对设置的所有Realm进行认证。
3.2.2 分支处理
根据不同的条件从多个Realm中选择一个进行认证处理
3.3 多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;
}
}
ManagerRealm
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;
}
}
在ShiroConfig.java中为SecurityManager配置多个Realm
@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 realms = new ArrayList<>();
realms.add(userRealm());
realms.add(managerRealm());
securityManager.setRealms(realms);
return securityManager;
}
//...
}
测试代码:
login.html
UserController.java
@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);
Subject subject = SecurityUtils.getSubject();
subject.login(token);
return "index";
}catch (Exception e){
return "login";
}
}
}
3.4 Shiro认证处理源码分析
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
this.assertRealmsConfigured();
Collection realms = this.getRealms();
// this.doMultiRealmAuthentication(realms, authenticationToken);中的realms参数就是认证会执行的Realm
return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);
}
3.5 多Realm配置(分支处理)
根据不同的条件执行不同的Realm
流程分析
|
实现案例:用户不同身份登录执行不同的Realm
自定义Realm(UserRealm\ManagerRealm)
当在登录页面选择“普通用户”登录,则执行UserRealm的认证
当在登录页面选择“管理员”登录,则执行ManagerRealm的认证
Realm的声明及配置
自定义Token
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 realms = this.getRealms();
MyToken token = (MyToken) authenticationToken;
String loginType = token.getLoginType(); // User
logger.info("------------------------------loginType:"+loginType);
Collection 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 realms = new ArrayList<>();
realms.add(userRealm());
realms.add(managerRealm());
securityManager.setRealms(realms);
return securityManager;
}
//...
}
测试:控制器接受数据进行认证
login.html
UserController.java
@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";
}
}
}
4.1 JSP应用
View JSP(Java Server Page)
Control Servlet
Model JDBC(Java Database Connection)
第一阶段的项目:JSP/Servlet+JDBC
4.2 SSM
View JSP
Control SpringMVC
Model MyBatis
第二阶段项目:JSP+SSM
4.3 SpringBoot
View Thymeleaf
Control SpringMVC
Model MyBatis/tkMapper
第三阶段练习项目:thymeleaf+SpringBoot(SSM)
单体项目:项目的前端页面与服务端的代码在同一个项目中(部署在同一个服务器上)
|
技术交流或者学习资源获取可加VX:
对于开发技术的技术语言学习,例如java、android、python等总结了一系列2020年的视频,希望大家工作中可以互相帮助,都是为了生活打拼,给自己一个机会、一点时间,工资翻一倍,生活还会像现在这么苦吗?