Enterprise authority management system

brief introduction

This project uses spring + spring MVC + mybatis framework integration for enterprise background permission management. The database uses mysql, and the front-end page uses JSP to rewrite based on the adminlte template.

Page display

Function introduction

Database introduction

The database uses mysql

It consists of userid and roleid, which are the foreign keys of users table and role table respectively, and are used to associate the many to many relationship between users and roles

It consists of permissionid and roleid, which are the foreign keys of permission table and role table respectively, and are used to associate the many to many relationship between resource permissions and roles.

SSM integration

Spring environment construction

Spring MVC environment construction

Spring and spring MVC integration

On the web In XML

Integration of spring and mybatis

Integration idea: configure the contents of the mybatis configuration file (mybatis. XML) into the spring configuration file.

SSM product operation

It mainly includes two functions: querying all products and adding products. The following is the flow chart of the two functions.

There are three ways to convert spring MVC parameter types

(spring 3.0 was used normally before, and later versions need to be registered with < MVC: annotation driven / >) use XML configuration to realize type conversion (system global converter)

(1) Register conversionservice

<!-- 注册ConversionService-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServicefactorybean">
    <property name="converters">
        <set>
            <bean class="com.ezubo.global.portal.util.StringToDateConverter">
                        <constructor-arg index="0" value="yyyy-MM-dd hh:mm"/>
            </bean>
        </set>
    </property>
</bean>

StringToDateConverter. Implementation of Java

public class StringToDateConverter implements Converter<String,Date> {

    private static final Logger logger = LoggerFactory.getLogger(StringToDateConverter.class);

    private String pattern;

    public StringToDateConverter(String pattern){
        this.pattern = pattern;
    }

    public Date convert(String s) {

        if(StringUtils.isBlank(s)){
            return null;
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        simpleDateFormat.setLenient(false);
        try{
            return simpleDateFormat.parse(s);
        }catch(ParseException e){
            logger.error("转换日期异常:"+e.getMessage(),e);
            throw new IllegalArgumentException("转换日期异常:"+e.getMessage(),e);
        }
    }
}

(2) Register conversionservice using configurablewebbindinginitializer

<!--使用 ConfigurableWebBindingInitializer 注册conversionService-->
<bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
	<property name="conversionService" ref="conversionService"/>
</bean>

(3) Register configurablewebbindinginitializer to requestmappinghandleradapter

<!-- 注册ConfigurableWebBindingInitializer 到RequestMappingHandlerAdapter-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="webBindingInitializer" ref="webBindingInitializer"/>
	<!-- 线程安全的访问session-->
	<property name="synchronizeOnSession" value="true"/>
</bean>

(normal after spring 3.2) use < MVC: annotation driven / > to register conversionservice

(1) Register conversionservice

<!-- 注册ConversionService-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServicefactorybean">
	<property name="converters">
		<set>
			<bean class="com.ezubo.global.portal.util.StringToDateConverter">
				<constructor-arg index="0" value="yyyy-MM-dd hh:mm"/>
			</bean>
		</set>
	</property>
</bean>

(2) You need to modify spring MVC In the annotation driven XML configuration file, add the attribute conversion service to point to the newly added conversion service.

<mvc:annotation-driven conversion-service="conversionService">
	<mvc:message-converters register-defaults="true">
		<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
			<property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>
			<!--转换时设置特性-->
			<property name="features">
				<array>
                    <!--避免默认的循环引用替换-->
                    <ref bean="DisableCircularReferenceDetect"/>
                    <ref bean="WriteMapNullValue"/>
                    <ref bean="WriteNullStringAsEmpty"/>
                    <ref bean="WriteNullNumberAsZero"/>
                </array>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

The first one is used in this project, which is relatively simple.

SSM order operation

Related functions of order operation:

Order query mainly completes simple multi table query. When querying an order, you need to query the information in other tables associated with the order. The following figure shows the order table and its associated table relationship.

The following figure shows the process of querying all orders:

The following figure shows the process of querying order details:

pageHelper

PageHelper is an excellent open-source mybatis paging plug-in in China. It supports basic mainstream and commonly used databases, such as mysql, Oracle, MariaDB, DB2, SQLite, HSQLDB, etc.

PageHelper is very simple to use. You only need to import dependencies and configure them in the spring configuration file.

Introduction to paging plug-in parameters:

There are six basic ways to use, and two are most commonly used:

List
list = sqlSession. selectList("x.y.selectIf",null,new RowBounds(1,10));

When using this calling method, you can use the rowboundaries parameter for paging. This method is the least invasive. Calling through rowboundaries only uses this parameter without adding anything else. When the paging plug-in detects that the rowboundaries parameter is used, the query will be physically paged.

For calling in this way, there are two special parameters for rowboundaries. Please refer to the above paging plug-in parameters for details.

Note: rowboundaries can be used not only in namespace mode, but also in interface mode. For example:

//这种情况下也会进行物理分页查询
List<Country> selectAll(RowBounds rowBounds);

This way calls pageHelper. before you need to paging the MyBatis query method. The static method of startpage is enough. The first mybatis query method immediately after this method will be paged.

For example:

//获取第1页,10条内容,默认查询总数count
pageHelper.startPage(1,10);
//紧跟着的第一个select方法会被分页
List<Country> list = countryMapper.selectIf(1);

The use steps are summarized as follows:

SSM permission Operation

It mainly involves the functions of three modules: user, role and resource permission. The following figure shows the relationship between the three tables.

Spring Security

The predecessor of spring security is Acegi security, which is a framework used by the spring project team to provide security authentication services.

Spring security provides comprehensive security services for enterprise applications based on J2EE. There are two main operations:

The quick start steps are as follows:

user management

User login

Use the database to complete the springsecurity user login process:

Spring security configuration

<security:authentication-manager>
	<security:authentication-provider user-service-ref="userService">
		<!-- 配置加密的方式
		<security:password-encoder ref="passwordEncoder"/>
		-->
	</security:authentication-provider>
</security:authentication-manager>

Service

@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
    
	@Autowired
	private IUserDao userDao;
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		UserInfo userInfo = userDao.findByUsername(username);
        List<Role> roles = userInfo.getRoles();
        List<SimpleGrantedAuthority> authoritys = getAuthority(roles);
        User user = new User(userInfo.getUsername(),"{noop}" + userInfo.getpassword(),userInfo.getStatus() == 0 ? false : true,true,authoritys);
        return user;
    }
    private List<SimpleGrantedAuthority> getAuthority(List<Role> roles) {
        List<SimpleGrantedAuthority> authoritys = new ArrayList();
        for (Role role : roles) {
        	authoritys.add(new SimpleGrantedAuthority(role.getRoleName()));
        }
        return authoritys;
    }
}

Dao

public interface IUserDao {
    @Select("select * from user where id=#{id}")
    public UserInfo findById(Long id) throws Exception;
    
    @Select("select * from user where username=#{username}")
    @Results({
        @Result(id = true,property = "id",column = "id"),@Result(column = "username",property = "username"),@Result(column = "email",property = "email"),@Result(column = "password",property = "password"),@Result(column = "phoneNum",property = "phoneNum"),@Result(column = "status",property = "status"),@Result(column = "id",property = "roles",javaType = List.class,many =
    		@Many(select = "com.itheima.ssm.dao.IRoleDao.findRoleByUserId")) })
    public UserInfo findByUsername(String username);
}

User exit

Using spring security to complete user exit is very simple

<security:logout invalidate-session="true" logout-url="/logout.do" logout-success-
url="/login.jsp" />
<a href="${pageContext.request.contextPath}/logout.do"
		class="btn btn-default btn-flat">注销</a>

User query

User add

<!-- 配置加密类 -->
<bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

User details

Dao

@Select("select * from user where id=#{id}")
@Results({ @Result(id = true,@Result(column ="password",@Result(column ="status",many =
@Many(select = "com.itheima.ssm.dao.IRoleDao.findRoleByUserId")) })
public UserInfo findById(Long id) throws Exception;

@Select("select * from role where id in( select roleId from user_role where userId=#{userId})")
@Results(
			{
				@Result(id=true,column="id",property="id"),@Result(column="roleName",property="roleName"),@Result(column="roleDesc",property="roleDesc"),@Result(column="id",property="permissions",javaType=List.class,many=@Many(select="com.itheima.ssm
                .dao.IPermissionDao.findByRoleId"))
})
public List<Role> findRoleByUserId(Long userId);

We need to query all roles and permissions of users, so we need to call findrolebyuserid in iroledao, and findbyroleid of ipermissiondao in iroledao

@Select("select * from permission where id in (select permissionId from role_permission where
roleId=#{roleId})")
public List<Permission> findByRoleId(Long roleId);

Role management

Role query

Role addition

Resource rights management

The resource permission query and the added process are the same as those of the role management module (refer to the figure above), except for different tables.

Association and control of permissions

User role Association

There is a many to many relationship between users and roles. To establish the relationship between them, we only need to create the user in the middle table_ Just insert data into the role.

The process is as follows:

Role permission Association

There is a many to many relationship between roles and permissions. To establish the relationship between them, we only need to create roles in the intermediate table_ Permission insert data.

The process and user role associations are the same, refer to the figure above.

Server side method level permission control

On the server side, we can control the permissions of methods through the annotations provided by spring security. Spring security supports three types of annotations on method permission control, jsr-250 annotation, @ secured annotation and annotation supporting expression. These three annotations are not enabled by default and need to be enabled separately through the corresponding attribute of the global method security element.

Open annotation usage

Jsr-250 notes

Example: @ rolesallowed ({"user", "admin"}) this method can be accessed as long as it has either "user" or "admin" permissions. You can omit the prefix role_, The actual permission may be role_ ADMIN

Comments supporting expressions

示例:
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)")
void changePassword(@P("userId") long userId ){ }
这里表示在changePassword方法执行之前,判断方法参数userId的值是否等于principal中保存的当前用户的userId,或者当前用户是否具有ROLE_ADMIN权限,两种符合其一,就可以访问该方法。
示例:
@PostAuthorize
User getUser("returnObject.userId == authentication.principal.userId or
hasPermission(returnObject,'ADMIN')");

@Secured annotation

示例:
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);
@Secured("ROLE_TELLER")

Page end label control permission

In the JSP page, we can use the permission tag provided by spring security for permission control

Import:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>version</version>
</dependency>
<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>

Common labels

In JSP, we can use the following three tags, where authentication represents the current authentication object and can obtain the current authentication object information, such as user name. The other two tags can be used for permission control

authentication
<security:authentication property="" htmlEscape="" scope="" var=""/>
authorize

Authorize is used to judge the general permission, and control the display of the content by judging whether the user has the corresponding permission

<security:authorize access="" method="" url="" var=""></security:authorize>
accesscontrollist

The access control list tag is used to authenticate ACL permissions. It defines three attributes: haspermission, domainobject and VaR, of which the first two must be specified

<security:accesscontrollist hasPermission="" domainObject="" var=""></security:accesscontrollist>

Ssmaop log

Based on AOP, the access time, operator user name, access IP, access resource URL, execution market and access method of each operation are obtained, stored in the database log table syslog and displayed on the page.

The process is as follows:

Create facet class processing log

@Component
@Aspect
public class LogAop {
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private ISysLogService sysLogService;
    
    private Date startTime; // 访问时间
    private Class executionClass;// 访问的类
    private Method executionMethod; // 访问的方法
    // 主要获取访问时间、访问的类、访问的方法
    
    @Before("execution(* com.itheima.ssm.controller.*.*(..))")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException,SecurityException {
        startTime = new Date(); // 访问时间
        // 获取访问的类
        executionClass = jp.getTarget().getClass();
        // 获取访问的方法
        String methodName = jp.getSignature().getName();// 获取访问的方法的名称
        Object[] args = jp.getArgs();// 获取访问的方法的参数
        if (args == null || args.length == 0) {// 无参数
        	executionMethod = executionClass.getmethod(methodName); // 只能获取无参数方法
        } else {
        	// 有参数,就将args中所有元素遍历,获取对应的Class,装入到一个Class[]
        	Class[] classArgs = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
				classArgs[i] = args[i].getClass();
			}
			executionMethod = executionClass.getmethod(methodName,classArgs);// 获取有参数方法
		}
	}
    // 主要获取日志中其它信息,时长、ip、url...
    @After("execution(* com.itheima.ssm.controller.*.*(..))")
    public void doAfter(JoinPoint jp) throws Exception {
        // 获取类上的@RequestMapping对象
        if (executionClass != SysLogController.class) {
        	RequestMapping classAnnotation = (RequestMapping)executionClass.getAnnotation(RequestMapping.class);
            if (classAnnotation != null) {
                // 获取方法上的@RequestMapping对象
                RequestMapping methodAnnotation = executionMethod.getAnnotation(RequestMapping.class);
                if (methodAnnotation != null) {
                    String url = ""; // 它的值应该是类上的@RequestMapping的value+方法上的@RequestMapping的value
                    url = classAnnotation.value()[0] + methodAnnotation.value()[0];
                    SysLog sysLog = new SysLog();
                    // 获取访问时长
                    Long executionTime = new Date().getTime() - startTime.getTime();
                    // 将sysLog对象属性封装
                    sysLog.setExecutionTime(executionTime);
                    sysLog.setUrl(url);
                    // 获取ip
                    String ip = request.getRemoteAddr();
                    sysLog.setIp(ip);
                    // 可以通过securityContext获取,也可以从request.getSession中获取
                    SecurityContext context = SecurityContextHolder.getContext(); //request.getSession().getAttribute("SPRING_Security_CONTEXT")
                    String username = ((User)
                    (context.getAuthentication().getPrincipal())).getUsername();
                    sysLog.setUsername(username);
                    sysLog.setMethod("[类名]" + executionClass.getName() + "[方法名]" +
                    executionMethod.getName());
                    sysLog.setVisitTime(startTime);
                    // 调用Service,调用dao将sysLog insert数据库
                    sysLogService.save(sysLog);
                }
            }
        }
    }
}

In the aspect class, we need to get the login user's username and IP address. What do we do?

SysLogController

@RequestMapping("/sysLog")
@Controller
public class SysLogController {
    @Autowired
    private ISysLogService sysLogService;
    @RequestMapping("/findAll.do")
    public ModelAndView findAll() throws Exception {
        ModelAndView mv = new ModelAndView();
        List<SysLog> sysLogs = sysLogService.findAll();
        mv.addObject("sysLogs",sysLogs);
        mv.setViewName("syslog-list");
        return mv;
	}
}

Service

@Service
@Transactional
public class SysLogServiceImpl implements ISysLogService {
    @Autowired
    private ISysLogDao sysLogDao;
    @Override
    public void save(SysLog log) throws Exception {
    	sysLogDao.save(log);
    }
    @Override
    public List<SysLog> findAll() throws Exception {
    	return sysLogDao.findAll();
    }
}

Dao

public interface ISysLogDao {
    @Select("select * from syslog")
    @Results({
        @Result(id=true,@Result(column="visitTime",property="visitTime"),@Result(column="ip",property="ip"),@Result(column="url",property="url"),@Result(column="executionTime",property="executionTime"),@Result(column="method",property="method"),@Result(column="username",property="username")
    })
	public List<SysLog> findAll() throws Exception;
	@Insert("insert into syslog(visitTime,username,ip,url,executionTime,method) values(#{visitTime},#{username},#{ip},#{url},#{executionTime},#{method})")
	public void save(SysLog log) throws Exception;
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>