activiti 7 包中包含了 SpringSecurity 所以不需要在引用。
一 用户登录
1 内存构建用户:
文件在正常运行代码的文件夹中。
package com.activitiweb;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 这是在内存构建用户
* */
@Configuration
public class DemoApplicationConfiguration {
private Logger logger = LoggerFactory.getLogger(DemoApplicationConfiguration.class);
@Bean
public UserDetailsService myUserDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
String[][] usersGroupsAndRoles = {
// 用户名 密码 用户角色 用户组
{"salaboy", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"bajie", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"wukong", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
{"admin", "password", "ROLE_ACTIVITI_ADMIN"},
};
for (String[] user : usersGroupsAndRoles) {
List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
}
return inMemoryUserDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
2 用数据库读取用户:
package com.imooc.activitiweb.security;
import com.imooc.activitiweb.pojo.UserInfoBean;
import com.imooc.activitiweb.mapper.UserInfoBeanMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
// 使用 org.springframework.stereotype 包下的Component
@Component
public class MyUserDetailsService implements UserDetailsService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
UserInfoBeanMapper mapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//-------------------------读取数据库判断登录-----------------------
/* SysUser sysUser = sysUserService.queryByUsername(username);
if (Objects.nonNull(sysUser)) {
return User.withUsername(username).password(sysUser.getEncodePassword())
.authorities(AuthorityUtils.NO_AUTHORITIES)
.build();
}
throw new UsernameNotFoundException("username: " + username + " notfound");*/
//------------------------根据code写死用户登录------------------------------
/*
//-----------------------正常的代码-----------------
logger.info("登录用户名:" + username);
// 在用户输入的密码进行一次加密才没有错
String passWord=passwordEncoder().encode("111");
logger.info("密码:" + passWord);
// 用户名 密码 用户角色
return new User(username,passWord, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ACTIVITI_USER"));
//-----------------------正常的代码-----------------
*/
//页面默认会对密码加密,数据库里如果在用户注册时,用的是加密过的密码,则直接读取比较即可
//return new User(username,"$2a$10$YFZDTqyBqwHkV/vTxKrhtuyIQCMD/joeIylCs8wbvXnhOYRgD/kDq", AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
//-------------------根据自定义用户属性登录-----------------------------
UserInfoBean userInfoBean = mapper.selectByUsername(username);
if (userInfoBean == null) {
throw new UsernameNotFoundException("数据库中无此用户!");
}
return userInfoBean;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
其中包含的 实体类 UserInfoBean
package com.activitiweb.pojo;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
@Component
public class UserInfoBean implements UserDetails {
private Long id;
public String name;
private String address;
private String username;
private String password;
private String roles;
/**
* 从数据库中取出roles字符串后,进行分解,构成一个GrantedAuthority的List返回
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.stream(roles.split(",")).map(e->new SimpleGrantedAuthority(e)).collect(Collectors.toSet());
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public String getAddress() {
return address;
}
}
其中包含的mapper类
package com.activitiweb.mapper;
import com.imooc.activitiweb.pojo.UserInfoBean;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;
@Mapper
@Component
public interface UserInfoBeanMapper {
/**
* 从数据库中查询用户
* @param username
* @return
*/
@Select("select * from user where username = #{username}")
UserInfoBean selectByUsername(@Param("username") String username);
}
二 SpringSecurity配置
配置:
package com.activitiweb.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class ActivitiSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private LoginSuccessHandler loginSuccessHandler;
@Autowired
private LoginFailureHandler loginFailureHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
//----------------自定义方法登录----------------------
/* http
.formLogin()
.loginPage("/authentication/require")//这个页面必须要放在resources/resources里,否则提交不会生效,估计是安全框架的机制
.loginProcessingUrl("/authentication/require")//这里的名字和登录页的Post内容一致,就可以调框架自带的登录
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler)
//.defaultSuccessUrl("/hello")
//.successForwardUrl("success.html")
//.failureForwardUrl("failure.html")
.and()
.authorizeRequests()
.antMatchers("/authentication/require", "/demo-login.html", "/demo-login1.html", "/demo-login").permitAll()
.anyRequest()
.authenticated()
.and()
.headers().frameOptions().disable()//让frame页面可以正常使用
.and()
.csrf().disable();*/
//--------------------------网页登录-----------------------------
/* http
.formLogin()
.loginPage("/demo-login.html")//这个页面必须要放在resources/resources里,否则提交不会生效,估计是安全框架的机制
.loginProcessingUrl("/demo-login")//这里的名字和登录页的Post内容一致,就可以调框架自带的登录
//.defaultSuccessUrl("/hello")
//.successForwardUrl("success.html")
//.failureForwardUrl("failure.html")
.and()
.authorizeRequests()
.antMatchers("/demo-login.html", "/demo-login").permitAll()
.anyRequest()
.authenticated()
.and()
.csrf().disable();
*/
//--------------------------验证都关闭-----------------------------
//http.authorizeRequests().anyRequest().permitAll().and().logout().permitAll().and().csrf().disable().headers().frameOptions().disable();//全部页面不验证
//--------------------------activiti与layui的自定义登录-----------------------------
http
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler)
//.defaultSuccessUrl("/hello")
//.successForwardUrl("success.html")
//.failureForwardUrl("failure.html")
.and()
.authorizeRequests()
.antMatchers("/login", "/demo-login.html", "/demo-login1.html", "/layuimini/page/login-1.html").permitAll()
.anyRequest()
.permitAll().and().logout().permitAll().and().csrf().disable().headers().frameOptions().disable();//全部页面不验证
}
}
登陆成功配置:
package com.activitiweb.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.activitiweb.util.AjaxResponse;
import com.imooc.activitiweb.util.GlobalConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component("loginSuccessHandler")
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 页面验证
* */
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
logger.info("登录成功1");
}
/**
* Ajax 验证
* */
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
logger.info("登录成功2");
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.getWriter().write(objectMapper.writeValueAsString(
AjaxResponse.AjaxData(GlobalConfig.ResponseCode.SUCCESS.getCode(),
GlobalConfig.ResponseCode.SUCCESS.getDesc(),
authentication.getName()
)));
}
}
登陆失败配置:
package com.activitiweb.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.activitiweb.util.AjaxResponse;
import com.imooc.activitiweb.util.GlobalConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component("loginFailureHandler")
public class LoginFailureHandler implements AuthenticationFailureHandler{
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
logger.info("登录失败");
httpServletResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.getWriter().write(objectMapper.writeValueAsString(
AjaxResponse.AjaxData(GlobalConfig.ResponseCode.ERROR.getCode(),
GlobalConfig.ResponseCode.ERROR.getDesc(),
"登录失败:"+e.getMessage()
)));
}
}
如果有人想访问你没有开放的接口,这个方法会帮你处理
package com.activitiweb.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
public class ActivitiSecurityController {
private Logger logger = LoggerFactory.getLogger(getClass());
private RequestCache requestCache = new HttpSessionRequestCache();
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
//估计是在springSecurity登录验证之后,对未登录用户跳转行为进行的判断。
@RequestMapping("/login")
@ResponseStatus(code = HttpStatus.UNAUTHORIZED)
public SimpleResponse requireAuthentication(HttpServletRequest request, HttpServletResponse response) {
/*SavedRequest savedRequest = requestCache.getRequest(request,response);
if(savedRequest != null){
String targetUrl = savedRequest.getRedirectUrl();
logger.info("引发跳转的请求是:"+targetUrl);
if(StringUtils.endsWithIgnoreCase(targetUrl,".html")){
try {
redirectStrategy.sendRedirect(request, response, "/demo-login.html");
}
catch(Exception e)
{
}
}
}*/
return new SimpleResponse("需要登录,使用/demo-login.html或发起post求情");
}
}