springboot+mybatis+shiro对url动态授权,同一账号登录,踢出最早登录(一)
老规矩开始之前的两问:干什么,为什么这么干
场景:
根本问题:任何多用户的系统都存在身份鉴权。简单来说,不同用户在同一个系统有不同的操作,那么系统必然要识别用户。
产生问题:身份识别之后,对于一个系统来说,就可以进行正常使用,但是这个时候任何人都可以获得系统的信息,这就产生了授权。
为什么使用shiro?
shiro是一款专门用来身份识别与授权的框架
shiro能干什么?
进行身份识别和授权
开始:
1:pom.xml 引入相关包
<dependency><groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>
2:首先是身份识别的问题,一般的我们都是通过输入的用户名和密码去数据库进行比对
那么对于shiro来说,我们只需要准备前端传的参数和数据库的参数,shiro就会为我们自动比对
(1)前端数据:
<from> <input name="username"/>
<input name="password">
<input type="submit">
</from>
(2) 数据库
CREATE TABLE `fsp_user` ( `UUID` varchar(50) NOT NULL,
`F_NICKNAME` varchar(100) DEFAULT NULL,
`F_PASSWORD` varchar(100) DEFAULT NULL,
PRIMARY KEY (`UUID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO
`fsp_user`
VALUES
("90feec5c-67bd-4fb2-b360-8b0387c4c009",
"admin",
"87632a5ef1d47286da9c1361717a1312");
(3)登录比对
这一步是由shiro来完成,shiro需要知道我们的 输入参数和数据库的数据
在此之前shiro需要初始化
shiro的中心管理器是SecurityManager,那么第一步就是要配置SecurityManager
@Beanpublic SecurityManager securityManager() {
//new 一个DefaultWebSecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
//realm 就是从数据库取出数据比对登录
defaultSecurityManager.setRealm(myShiroRealm());
//session管理器
defaultSecurityManager.setSessionManager(sessionManager());
//cache管理器
defaultSecurityManager.setCacheManager(cacheManager());
//我们需要对密码进行加密 使用md5,加密10次
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher("md5");
hashedCredentialsMatcher.setHashIterations(10);
myShiroRealm().setCredentialsMatcher(hashedCredentialsMatcher);
SecurityUtils.setSecurityManager(defaultSecurityManager);
return defaultSecurityManager;
}
@Bean//session 管理器
public DefaultWebSessionManager sessionManager(){
DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
SimpleCookie simpleCookie= new SimpleCookie();
simpleCookie.setName("jeesite.session.id");
defaultWebSessionManager.setSessionIdCookie(simpleCookie);
defaultWebSessionManager.setSessionDAO(sessionDAO());
return defaultWebSessionManager;
}
//session的增删改查操作
@Bean
public MemorySessionDAO sessionDAO(){
return new MemorySessionDAO();
}
//cache管理器
@Bean
public CacheManager cacheManager(){
return new EhCacheManager();
}
@Bean//取出数据库的数据 这个是我们自定义的
public UserRealm myShiroRealm(){
return new UserRealm();
}
//我们定义的数据源集成自AuthorizingRealmpublic class UserRealm extends AuthorizingRealm {
private Logger logger = LoggerFactory.getLogger(AuthorizingRealm.class);
//数据库fsp_user 表对应的mybatis mapper接口
@Autowired
private FspUserDao fspUserDao;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
return authorizationInfo;
}
//登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1,获得前端传值
String username = (String) authenticationToken.getPrincipal();
//去数据库查询
FspUser user = fspUserDao.isSelect("F_IPONE",username);
if (user == null) {
//没找到帐号
throw new UnknownAccountException();
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getF_PASSWORD(), "");
//盐
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("GGZEServer"));
user.setF_PASSWORD("");
//将用户信息放入session中
SecurityUtils.getSubject().getSession().setTimeout(-5000);
SecurityUtils.getSubject().getSession().setAttribute("FSPUSER", user);
return authenticationInfo;
}
/*//加密
public static void main(String[] args){
Md5Hash md5Hash = new Md5Hash("123456","GGZEServer",10);
System.out.println(md5Hash.toString());
}*/
}
(4)配置完成后,我们需要让所有的请求都是合法的,就必须进行登录,记住登录信息,每次的请求验证其合法性
我们使用过滤器来过滤所有请求,
首先要使shiro认识我们自定义的过滤器
@Beanpublic AutoShiro shirFilter(SecurityManager securityManager, FspDataRecordDao fspDataRecordDao) {
System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 过滤器链11
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//key 为访问地址,value为权限。anao全部不过滤 authc为需要登录 loingout为登出
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/login", "authc");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/loginout", "loginout");
shiroFilterFactoryBean.setSecurityManager(securityManager);
//登录地址设置
shiroFilterFactoryBean.setLoginUrl("/vsp_8201574998956");
//成功地址设置
shiroFilterFactoryBean.setSuccessUrl("/vsp_8201574998957");
Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
AuthFilter authFilter=new AuthFilter();
authFilter.setLoginUrl("/login");
authFilter.setUsernameParam("F_IPONE");
authFilter.setPasswordParam("F_PASSWORD");
authFilter.setUserClass(FspUser.class);
//设置过滤器名
filters.put("authc", authFilter);
//这里可以设置自定义的过滤器
//设置登出
LogoutFilter logoutFilter=new LogoutFilter();
filters.put("loginout",logoutFilter);
shiroFilterFactoryBean.setFilters(filters);
return shiroFilterFactoryBean;
}
按以上配置,shiro会认知shiro的过滤器,我们来实现它的过滤器
public class AuthFilter extends FormAuthenticationFilter {private Class<? extends FspUser> userClass;
private static final String REDIRECT_URL_PARAMETER_NAME = "redirectUrl";
//创建身份认证
@Override
protected org.apache.shiro.authc.AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) {
String username = getUsername(servletRequest);
String password = getPassword(servletRequest);
boolean rememberMe = isRememberMe(servletRequest);
String host = getHost(servletRequest);
return new UsernamePasswordToken(username, password, rememberMe, host);
}
/**
* 是否允许访问
*
* @param servletRequest ServletRequest
* @param servletResponse ServletResponse
* @param mappedValue 映射值
* @return 是否允许访问
*/
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) {
Subject subject = getSubject(servletRequest, servletResponse);
Object principal = subject != null ? subject.getPrincipal() : null;
if (principal == null || !FspUser.class.isAssignableFrom(principal.getClass())) {
return false;
}
HttpServletRequest request=(HttpServletRequest) servletRequest;
if(request.getServletPath().indexOf("login")>=0&&request.getSession().getAttribute("FSPUSER")!=null){
HttpServletResponse response = (HttpServletResponse)servletResponse;
try {
response.sendRedirect("/shopc/vsp_8201574998957");
} catch (IOException e) {
e.printStackTrace();
}
}
return super.isAccessAllowed(servletRequest, servletResponse, mappedValue);
}
/**
* 拒绝访问处理
*
* @param servletRequest ServletRequest
* @param servletResponse ServletResponse
* @return 是否继续处理
*/
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
return executeLogin(request, response);
} else {
return true;
}
}
response.sendRedirect("/shopc/vsp_8201574998956");
return false;
}
/**
* 登录成功处理
*
* @param authenticationToken 令牌
* @param subject Subject
* @param servletRequest ServletRequest
* @param servletResponse ServletResponse
* @return 是否继续处理
*/
@Override
protected boolean onLoginSuccess(org.apache.shiro.authc.AuthenticationToken authenticationToken, Subject subject, ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
return super.onLoginSuccess(authenticationToken, subject, servletRequest, servletResponse);
}
/**
* 登录失败处理
*
* @param authenticationToken 令牌
* @param authenticationException 认证异常
* @param servletRequest ServletRequest
* @param servletResponse ServletResponse
* @return 是否继续处理
*/
@Override
protected boolean onLoginFailure(org.apache.shiro.authc.AuthenticationToken authenticationToken, AuthenticationException authenticationException, ServletRequest servletRequest, ServletResponse servletResponse) {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
return super.onLoginFailure(authenticationToken, authenticationException, servletRequest, servletResponse);
}
public Class<? extends FspUser> getUserClass() {
return userClass;
}
public void setUserClass(Class<? extends FspUser> userClass) {
this.userClass = userClass;
}
public static String getRedirectUrlParameterName() {
return REDIRECT_URL_PARAMETER_NAME;
}
当执行创建身份认证的时候return new UsernamePasswordToken(username, password, rememberMe, host);
会进去我们自定义的Realm 登录成功。
已上传码云:https://gitee.com/wervernice/shirotest
未完待续
以上是 springboot+mybatis+shiro对url动态授权,同一账号登录,踢出最早登录(一) 的全部内容, 来源链接: utcz.com/z/512629.html